diff --git a/src/mesh/Connectivity.cpp b/src/mesh/Connectivity.cpp
index 0a02886dd673680a7c800d549b5ee3fc9aacd07a..a819af495a1dbb358a2705231e3ff30f2bcbed02 100644
--- a/src/mesh/Connectivity.cpp
+++ b/src/mesh/Connectivity.cpp
@@ -7,8 +7,7 @@
 #include <map>
 
 template <size_t Dimension>
-Connectivity<Dimension>::Connectivity()
-{}
+Connectivity<Dimension>::Connectivity() = default;
 
 template <size_t Dimension>
 void
@@ -22,6 +21,22 @@ Connectivity<Dimension>::_buildFrom(const ConnectivityDescriptor& descriptor)
     Assert(descriptor.face_owner_vector.size() == descriptor.face_number_vector.size());
   }
 
+  m_number_of_cells = descriptor.cell_number_vector.size();
+  m_number_of_nodes = descriptor.node_number_vector.size();
+
+  if constexpr (Dimension == 1) {
+    m_number_of_edges = m_number_of_nodes;
+    m_number_of_faces = m_number_of_nodes;
+  } else {
+    m_number_of_faces = descriptor.face_number_vector.size();
+    if constexpr (Dimension == 2) {
+      m_number_of_edges = m_number_of_faces;
+    } else {
+      static_assert(Dimension == 3, "unexpected dimension");
+      m_number_of_edges = descriptor.edge_number_vector.size();
+    }
+  }
+
   auto& cell_to_node_matrix = m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::node)];
   cell_to_node_matrix       = descriptor.cell_to_node_vector;
 
diff --git a/src/mesh/Connectivity.hpp b/src/mesh/Connectivity.hpp
index f1e8c9f2dcc9e883987fde4fc69baed16971dbd0..51cda422736b932d7d2277344eadad19e4e60213 100644
--- a/src/mesh/Connectivity.hpp
+++ b/src/mesh/Connectivity.hpp
@@ -47,6 +47,11 @@ class Connectivity final : public IConnectivity
   }
 
  private:
+  size_t m_number_of_cells;
+  size_t m_number_of_faces;
+  size_t m_number_of_edges;
+  size_t m_number_of_nodes;
+
   ConnectivityMatrix m_item_to_item_matrix[Dimension + 1][Dimension + 1];
   WeakCellValue<const CellType> m_cell_type;
 
@@ -639,38 +644,28 @@ class Connectivity final : public IConnectivity
   size_t
   numberOfNodes() const final
   {
-    const auto& node_to_cell_matrix = this->_getMatrix(ItemType::node, ItemType::cell);
-    return node_to_cell_matrix.numRows();
+    return m_number_of_nodes;
   }
 
   PUGS_INLINE
   size_t
   numberOfEdges() const final
   {
-    if constexpr (Dimension == 1) {
-      return this->numberOfNodes();
-    } else if constexpr (Dimension == 2) {
-      return this->numberOfFaces();
-    } else {
-      const auto& edge_to_node_matrix = this->_getMatrix(ItemType::edge, ItemType::node);
-      return edge_to_node_matrix.numRows();
-    }
+    return m_number_of_edges;
   }
 
   PUGS_INLINE
   size_t
   numberOfFaces() const final
   {
-    const auto& face_to_node_matrix = this->_getMatrix(ItemType::face, ItemType::cell);
-    return face_to_node_matrix.numRows();
+    return m_number_of_faces;
   }
 
   PUGS_INLINE
   size_t
   numberOfCells() const final
   {
-    const auto& cell_to_node_matrix = this->_getMatrix(ItemType::cell, ItemType::node);
-    return cell_to_node_matrix.numRows();
+    return m_number_of_cells;
   }
 
   template <ItemType item_type>
diff --git a/tests/test_Connectivity.cpp b/tests/test_Connectivity.cpp
index 9abb8fdb3aa0f81bc6123daf70dd467006657f54..dcc979dd9f833d00ff97ac50816b5102b3ec3e2f 100644
--- a/tests/test_Connectivity.cpp
+++ b/tests/test_Connectivity.cpp
@@ -12,6 +12,120 @@
 
 TEST_CASE("Connectivity", "[mesh]")
 {
+  SECTION("numberOfItems")
+  {
+    SECTION("1D")
+    {
+      SECTION("unordered 1D mesh")
+      {
+        const auto& mesh = *MeshDataBaseForTests::get().unordered1DMesh();
+
+        if (parallel::size() == 1) {
+          REQUIRE(mesh.numberOfNodes() == 35);
+          REQUIRE(mesh.numberOfEdges() == 35);
+          REQUIRE(mesh.numberOfFaces() == 35);
+          REQUIRE(mesh.numberOfCells() == 34);
+        }
+
+        REQUIRE(mesh.numberOfNodes() == mesh.numberOf<ItemType::node>());
+        REQUIRE(mesh.numberOfEdges() == mesh.numberOf<ItemType::edge>());
+        REQUIRE(mesh.numberOfFaces() == mesh.numberOf<ItemType::face>());
+        REQUIRE(mesh.numberOfCells() == mesh.numberOf<ItemType::cell>());
+      }
+
+      SECTION("cartesian 1D mesh")
+      {
+        const auto& mesh = *MeshDataBaseForTests::get().cartesian1DMesh();
+
+        if (parallel::size() == 1) {
+          REQUIRE(mesh.numberOfNodes() == 24);
+          REQUIRE(mesh.numberOfEdges() == 24);
+          REQUIRE(mesh.numberOfFaces() == 24);
+          REQUIRE(mesh.numberOfCells() == 23);
+        }
+
+        REQUIRE(mesh.numberOfNodes() == mesh.numberOf<ItemType::node>());
+        REQUIRE(mesh.numberOfEdges() == mesh.numberOf<ItemType::edge>());
+        REQUIRE(mesh.numberOfFaces() == mesh.numberOf<ItemType::face>());
+        REQUIRE(mesh.numberOfCells() == mesh.numberOf<ItemType::cell>());
+      }
+    }
+
+    SECTION("2D")
+    {
+      SECTION("hybrid 2D mesh")
+      {
+        const auto& mesh = *MeshDataBaseForTests::get().hybrid2DMesh();
+
+        if (parallel::size() == 1) {
+          REQUIRE(mesh.numberOfNodes() == 53);
+          REQUIRE(mesh.numberOfEdges() == 110);
+          REQUIRE(mesh.numberOfFaces() == 110);
+          REQUIRE(mesh.numberOfCells() == 58);
+        }
+
+        REQUIRE(mesh.numberOfNodes() == mesh.numberOf<ItemType::node>());
+        REQUIRE(mesh.numberOfEdges() == mesh.numberOf<ItemType::edge>());
+        REQUIRE(mesh.numberOfFaces() == mesh.numberOf<ItemType::face>());
+        REQUIRE(mesh.numberOfCells() == mesh.numberOf<ItemType::cell>());
+      }
+
+      SECTION("cartesian 2D mesh")
+      {
+        const auto& mesh = *MeshDataBaseForTests::get().cartesian2DMesh();
+
+        if (parallel::size() == 1) {
+          REQUIRE(mesh.numberOfNodes() == 56);
+          REQUIRE(mesh.numberOfEdges() == 97);
+          REQUIRE(mesh.numberOfFaces() == 97);
+          REQUIRE(mesh.numberOfCells() == 42);
+        }
+
+        REQUIRE(mesh.numberOfNodes() == mesh.numberOf<ItemType::node>());
+        REQUIRE(mesh.numberOfEdges() == mesh.numberOf<ItemType::edge>());
+        REQUIRE(mesh.numberOfFaces() == mesh.numberOf<ItemType::face>());
+        REQUIRE(mesh.numberOfCells() == mesh.numberOf<ItemType::cell>());
+      }
+    }
+
+    SECTION("3D")
+    {
+      SECTION("hybrid 3D mesh")
+      {
+        const auto& mesh = *MeshDataBaseForTests::get().hybrid3DMesh();
+
+        if (parallel::size() == 1) {
+          REQUIRE(mesh.numberOfNodes() == 132);
+          REQUIRE(mesh.numberOfEdges() == 452);
+          REQUIRE(mesh.numberOfFaces() == 520);
+          REQUIRE(mesh.numberOfCells() == 199);
+        }
+
+        REQUIRE(mesh.numberOfNodes() == mesh.numberOf<ItemType::node>());
+        REQUIRE(mesh.numberOfEdges() == mesh.numberOf<ItemType::edge>());
+        REQUIRE(mesh.numberOfFaces() == mesh.numberOf<ItemType::face>());
+        REQUIRE(mesh.numberOfCells() == mesh.numberOf<ItemType::cell>());
+      }
+
+      SECTION("cartesian 3D mesh")
+      {
+        const auto& mesh = *MeshDataBaseForTests::get().cartesian3DMesh();
+
+        if (parallel::size() == 1) {
+          REQUIRE(mesh.numberOfNodes() == 280);
+          REQUIRE(mesh.numberOfEdges() == 709);
+          REQUIRE(mesh.numberOfFaces() == 598);
+          REQUIRE(mesh.numberOfCells() == 168);
+        }
+
+        REQUIRE(mesh.numberOfNodes() == mesh.numberOf<ItemType::node>());
+        REQUIRE(mesh.numberOfEdges() == mesh.numberOf<ItemType::edge>());
+        REQUIRE(mesh.numberOfFaces() == mesh.numberOf<ItemType::face>());
+        REQUIRE(mesh.numberOfCells() == mesh.numberOf<ItemType::cell>());
+      }
+    }
+  }
+
   SECTION("isOwned")
   {
     SECTION("1D")