From 11139a1ee8565ef0f5d9afd6230e4ad70bfe11d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Fri, 16 Feb 2024 17:57:21 +0100
Subject: [PATCH] Get rid of IMesh (mesh interface class) and use MeshVariant
 instead

This simplifies in some sense it reduces the number of dynamic_cast
and allow some automatic type checking
---
 src/language/modules/MeshModule.cpp           | 151 +++++------------
 src/language/modules/MeshModule.hpp           |   4 +-
 src/language/modules/SchemeModule.cpp         | 110 +++++-------
 src/language/modules/WriterModule.cpp         |  41 ++---
 .../EmbeddedDiscreteFunctionMathFunctions.cpp |  53 ++----
 src/language/utils/IntegrateCellValue.hpp     |  58 +++++++
 .../ItemArrayVariantFunctionInterpoler.cpp    |  57 +++----
 .../ItemArrayVariantFunctionInterpoler.hpp    |  13 +-
 .../ItemValueVariantFunctionInterpoler.cpp    |  57 +++----
 .../ItemValueVariantFunctionInterpoler.hpp    |  13 +-
 src/mesh/CMakeLists.txt                       |   6 +-
 src/mesh/CartesianMeshBuilder.cpp             |   3 +-
 src/mesh/DiamondDualMeshBuilder.cpp           |  47 +++---
 src/mesh/DiamondDualMeshBuilder.hpp           |   9 +-
 src/mesh/Dual1DMeshBuilder.cpp                |  24 ++-
 src/mesh/Dual1DMeshBuilder.hpp                |   8 +-
 src/mesh/DualMeshManager.cpp                  | 117 ++++++-------
 src/mesh/DualMeshManager.hpp                  |  17 +-
 src/mesh/GmshReader.cpp                       |   9 +-
 src/mesh/GmshReader.hpp                       |   1 -
 src/mesh/IMesh.cpp                            |  10 --
 src/mesh/IMesh.hpp                            |  28 ---
 src/mesh/MedianDualMeshBuilder.cpp            |  43 +++--
 src/mesh/MedianDualMeshBuilder.hpp            |   9 +-
 src/mesh/Mesh.cpp                             |  16 ++
 src/mesh/Mesh.hpp                             |  47 +++++-
 src/mesh/MeshBuilderBase.cpp                  |   9 +-
 src/mesh/MeshBuilderBase.hpp                  |   6 +-
 src/mesh/MeshData.cpp                         |   4 +-
 src/mesh/MeshDataManager.cpp                  |  14 +-
 src/mesh/MeshDataManager.hpp                  |   6 +-
 src/mesh/MeshRandomizer.cpp                   |  88 ++++------
 src/mesh/MeshRandomizer.hpp                   |  13 +-
 src/mesh/MeshRelaxer.cpp                      |  63 +++----
 src/mesh/MeshRelaxer.hpp                      |  16 +-
 src/mesh/MeshSmoother.cpp                     | 159 +++++-------------
 src/mesh/MeshSmoother.hpp                     |  21 ++-
 src/mesh/MeshTraits.hpp                       |  21 +++
 src/mesh/MeshTransformer.cpp                  |  45 ++---
 src/mesh/MeshTransformer.hpp                  |  10 +-
 src/mesh/MeshUtils.cpp                        |  12 ++
 src/mesh/MeshUtils.hpp                        |  10 ++
 src/mesh/MeshVariant.cpp                      |  17 ++
 src/mesh/MeshVariant.hpp                      |  56 ++++++
 src/output/GnuplotWriter.cpp                  |  76 ++++-----
 src/output/GnuplotWriter.hpp                  |   8 +-
 src/output/GnuplotWriter1D.cpp                |  68 ++++----
 src/output/GnuplotWriter1D.hpp                |   8 +-
 src/output/IWriter.hpp                        |  12 +-
 src/output/VTKWriter.cpp                      |  61 +------
 src/output/VTKWriter.hpp                      |   8 +-
 src/output/WriterBase.cpp                     |  96 ++++-------
 src/output/WriterBase.hpp                     |  24 +--
 src/scheme/AcousticSolver.cpp                 |  60 ++++---
 src/scheme/AcousticSolver.hpp                 |   8 +-
 src/scheme/DiscreteFunctionIntegrator.cpp     |  73 ++++----
 src/scheme/DiscreteFunctionIntegrator.hpp     |  16 +-
 src/scheme/DiscreteFunctionInterpoler.cpp     |  65 ++++---
 src/scheme/DiscreteFunctionInterpoler.hpp     |  16 +-
 src/scheme/DiscreteFunctionP0.hpp             |   3 +-
 src/scheme/DiscreteFunctionP0Vector.hpp       |   2 +-
 src/scheme/DiscreteFunctionUtils.cpp          |  85 +++++-----
 src/scheme/DiscreteFunctionUtils.hpp          |   7 +-
 .../DiscreteFunctionVectorIntegrator.cpp      |  46 +++--
 .../DiscreteFunctionVectorIntegrator.hpp      |  16 +-
 .../DiscreteFunctionVectorInterpoler.cpp      |  46 +++--
 .../DiscreteFunctionVectorInterpoler.hpp      |  16 +-
 src/scheme/FluxingAdvectionSolver.cpp         |  38 ++---
 src/scheme/FluxingAdvectionSolver.hpp         |   7 +-
 src/scheme/HyperelasticSolver.cpp             |  89 +++++-----
 src/scheme/HyperelasticSolver.hpp             |  12 +-
 src/utils/GlobalVariableManager.hpp           |   8 +
 tests/MeshDataBaseForTests.cpp                |  36 ++--
 tests/MeshDataBaseForTests.hpp                |  49 +++---
 tests/test_CellIntegrator.cpp                 |  24 +--
 tests/test_Connectivity.cpp                   |  59 +++----
 tests/test_DiamondDualConnectivityBuilder.cpp |   4 +-
 tests/test_DiamondDualMeshBuilder.cpp         |  16 +-
 tests/test_DiscreteFunctionIntegrator.cpp     | 126 +++++++-------
 .../test_DiscreteFunctionIntegratorByZone.cpp |  69 ++++----
 tests/test_DiscreteFunctionInterpoler.cpp     |  69 ++++----
 .../test_DiscreteFunctionInterpolerByZone.cpp |  69 ++++----
 tests/test_DiscreteFunctionP0.cpp             |  46 ++---
 tests/test_DiscreteFunctionP0Vector.cpp       |  36 ++--
 tests/test_DiscreteFunctionUtils.cpp          | 137 ++++++++-------
 .../test_DiscreteFunctionVectorIntegrator.cpp |  22 ++-
 ...DiscreteFunctionVectorIntegratorByZone.cpp |  15 +-
 .../test_DiscreteFunctionVectorInterpoler.cpp |  24 +--
 ...DiscreteFunctionVectorInterpolerByZone.cpp |  24 +--
 tests/test_Dual1DConnectivityBuilder.cpp      |   2 +-
 tests/test_Dual1DMeshBuilder.cpp              |   8 +-
 tests/test_DualConnectivityManager.cpp        |   4 +-
 tests/test_DualMeshManager.cpp                |  63 +++----
 tests/test_EdgeIntegrator.cpp                 |  33 ++--
 ...mbeddedDiscreteFunctionMathFunctions1D.cpp |   2 +-
 ...mbeddedDiscreteFunctionMathFunctions2D.cpp |   2 +-
 ...mbeddedDiscreteFunctionMathFunctions3D.cpp |   2 +-
 ...st_EmbeddedDiscreteFunctionOperators1D.cpp |   2 +-
 ...st_EmbeddedDiscreteFunctionOperators2D.cpp |   2 +-
 ...st_EmbeddedDiscreteFunctionOperators3D.cpp |   2 +-
 tests/test_EmbeddedDiscreteFunctionUtils.cpp  |   4 +-
 tests/test_FaceIntegrator.cpp                 |  19 ++-
 tests/test_IntegrateCellArray.cpp             |  27 +--
 tests/test_IntegrateCellValue.cpp             |  27 +--
 tests/test_IntegrateOnCells.cpp               |  81 +++++----
 tests/test_InterpolateItemArray.cpp           |  45 +++--
 tests/test_InterpolateItemValue.cpp           |  20 ++-
 tests/test_ItemArray.cpp                      |  33 ++--
 tests/test_ItemArrayUtils.cpp                 |  42 +++--
 tests/test_ItemArrayVariant.cpp               |   3 +-
 ...est_ItemArrayVariantFunctionInterpoler.cpp |  43 ++---
 tests/test_ItemValue.cpp                      |  33 ++--
 tests/test_ItemValueUtils.cpp                 |  48 ++++--
 tests/test_ItemValueVariant.cpp               |   5 +-
 ...est_ItemValueVariantFunctionInterpoler.cpp |  41 ++---
 tests/test_MedianDualConnectivityBuilder.cpp  |   2 +-
 tests/test_MedianDualMeshBuilder.cpp          |   8 +-
 tests/test_MeshEdgeBoundary.cpp               |  20 +--
 tests/test_MeshEdgeInterface.cpp              |   8 +-
 tests/test_MeshFaceBoundary.cpp               |  20 +--
 tests/test_MeshFaceInterface.cpp              |  14 +-
 tests/test_MeshFlatEdgeBoundary.cpp           |  33 ++--
 tests/test_MeshFlatFaceBoundary.cpp           |  33 ++--
 tests/test_MeshFlatNodeBoundary.cpp           |  39 +++--
 tests/test_MeshLineEdgeBoundary.cpp           |  29 ++--
 tests/test_MeshLineFaceBoundary.cpp           |  13 +-
 tests/test_MeshLineNodeBoundary.cpp           |  29 ++--
 tests/test_MeshNodeBoundary.cpp               |  20 +--
 tests/test_MeshNodeInterface.cpp              |  14 +-
 tests/test_ParallelChecker_read.cpp           |  44 ++---
 tests/test_ParallelChecker_write.cpp          |  24 +--
 ...malToDiamondDualConnectivityDataMapper.cpp |   6 +-
 ...t_PrimalToDual1DConnectivityDataMapper.cpp |   2 +-
 ...imalToMedianDualConnectivityDataMapper.cpp |   4 +-
 tests/test_SubItemArrayPerItem.cpp            |  22 +--
 tests/test_SubItemArrayPerItemUtils.cpp       |  28 +--
 tests/test_SubItemArrayPerItemVariant.cpp     |   2 +-
 tests/test_SubItemValuePerItem.cpp            |  26 +--
 tests/test_SubItemValuePerItemUtils.cpp       |  26 +--
 tests/test_SubItemValuePerItemVariant.cpp     |   2 +-
 tests/test_Synchronizer.cpp                   |  36 ++--
 141 files changed, 2233 insertions(+), 2184 deletions(-)
 delete mode 100644 src/mesh/IMesh.cpp
 delete mode 100644 src/mesh/IMesh.hpp
 create mode 100644 src/mesh/Mesh.cpp
 create mode 100644 src/mesh/MeshTraits.hpp
 create mode 100644 src/mesh/MeshUtils.cpp
 create mode 100644 src/mesh/MeshUtils.hpp
 create mode 100644 src/mesh/MeshVariant.cpp
 create mode 100644 src/mesh/MeshVariant.hpp

diff --git a/src/language/modules/MeshModule.cpp b/src/language/modules/MeshModule.cpp
index 9f709e2fd..548f42dda 100644
--- a/src/language/modules/MeshModule.cpp
+++ b/src/language/modules/MeshModule.cpp
@@ -23,6 +23,8 @@
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshRelaxer.hpp>
 #include <mesh/MeshTransformer.hpp>
+#include <mesh/MeshUtils.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <mesh/NamedBoundaryDescriptor.hpp>
 #include <mesh/NamedInterfaceDescriptor.hpp>
 #include <mesh/NamedZoneDescriptor.hpp>
@@ -37,7 +39,7 @@
 
 MeshModule::MeshModule()
 {
-  this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IMesh>>);
+  this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const MeshVariant>>);
   this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IBoundaryDescriptor>>);
   this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IInterfaceDescriptor>>);
   this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IZoneDescriptor>>);
@@ -83,7 +85,7 @@ MeshModule::MeshModule()
 
   this->_addBuiltinFunction("readGmsh", std::function(
 
-                                          [](const std::string& file_name) -> std::shared_ptr<const IMesh> {
+                                          [](const std::string& file_name) -> std::shared_ptr<const MeshVariant> {
                                             GmshReader gmsh_reader(file_name);
                                             return gmsh_reader.mesh();
                                           }
@@ -140,42 +142,44 @@ MeshModule::MeshModule()
 
                                           ));
 
-  this->_addBuiltinFunction("interpolate",
-                            std::function(
+  this
+    ->_addBuiltinFunction("interpolate",
+                          std::function(
 
-                              [](std::shared_ptr<const IMesh> mesh, std::shared_ptr<const ItemType> item_type,
-                                 const FunctionSymbolId& function_id) -> std::shared_ptr<const ItemValueVariant> {
-                                return ItemValueVariantFunctionInterpoler{mesh, *item_type, function_id}.interpolate();
-                              }
+                            [](std::shared_ptr<const MeshVariant> mesh_v, std::shared_ptr<const ItemType> item_type,
+                               const FunctionSymbolId& function_id) -> std::shared_ptr<const ItemValueVariant> {
+                              return ItemValueVariantFunctionInterpoler{mesh_v, *item_type, function_id}.interpolate();
+                            }
 
-                              ));
+                            ));
 
   this->_addBuiltinFunction(
     "interpolate_array",
     std::function(
 
-      [](std::shared_ptr<const IMesh> mesh, std::shared_ptr<const ItemType> item_type,
+      [](std::shared_ptr<const MeshVariant> mesh_v, std::shared_ptr<const ItemType> item_type,
          const std::vector<FunctionSymbolId>& function_id_list) -> std::shared_ptr<const ItemArrayVariant> {
-        return ItemArrayVariantFunctionInterpoler{mesh, *item_type, function_id_list}.interpolate();
+        return ItemArrayVariantFunctionInterpoler{mesh_v, *item_type, function_id_list}.interpolate();
       }
 
       ));
 
-  this->_addBuiltinFunction("transform", std::function(
+  this->_addBuiltinFunction("transform",
+                            std::function(
 
-                                           [](std::shared_ptr<const IMesh> p_mesh,
-                                              const FunctionSymbolId& function_id) -> std::shared_ptr<const IMesh> {
-                                             return MeshTransformer{}.transform(function_id, p_mesh);
-                                           }
+                              [](std::shared_ptr<const MeshVariant> mesh_v,
+                                 const FunctionSymbolId& function_id) -> std::shared_ptr<const MeshVariant> {
+                                return MeshTransformer{}.transform(function_id, mesh_v);
+                              }
 
-                                           ));
+                              ));
 
   this->_addBuiltinFunction("relax", std::function(
 
-                                       [](const std::shared_ptr<const IMesh>& source_mesh,
-                                          const std::shared_ptr<const IMesh>& destination_mesh,
-                                          const double& theta) -> std::shared_ptr<const IMesh> {
-                                         return MeshRelaxer{}.relax(source_mesh, destination_mesh, theta);
+                                       [](const std::shared_ptr<const MeshVariant>& source_mesh_v,
+                                          const std::shared_ptr<const MeshVariant>& destination_mesh_v,
+                                          const double& theta) -> std::shared_ptr<const MeshVariant> {
+                                         return MeshRelaxer{}.relax(source_mesh_v, destination_mesh_v, theta);
                                        }
 
                                        ));
@@ -183,30 +187,8 @@ MeshModule::MeshModule()
   this->_addBuiltinFunction("check_connectivity_ordering",
                             std::function(
 
-                              [](const std::shared_ptr<const IMesh>& i_mesh) -> bool {
-                                switch (i_mesh->dimension()) {
-                                case 1: {
-                                  using MeshType = Mesh<Connectivity<1>>;
-
-                                  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
-                                  return checkConnectivityOrdering(p_mesh->connectivity());
-                                }
-                                case 2: {
-                                  using MeshType = Mesh<Connectivity<2>>;
-
-                                  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
-                                  return checkConnectivityOrdering(p_mesh->connectivity());
-                                }
-                                case 3: {
-                                  using MeshType = Mesh<Connectivity<3>>;
-
-                                  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
-                                  return checkConnectivityOrdering(p_mesh->connectivity());
-                                }
-                                default: {
-                                  throw UnexpectedError("invalid dimension");
-                                }
-                                }
+                              [](const std::shared_ptr<const MeshVariant>& mesh_v) -> bool {
+                                return checkConnectivityOrdering(mesh_v);
                               }
 
                               ));
@@ -215,7 +197,7 @@ MeshModule::MeshModule()
                             std::function(
 
                               [](const TinyVector<1> a, const TinyVector<1> b,
-                                 const std::vector<uint64_t>& box_sizes) -> std::shared_ptr<const IMesh> {
+                                 const std::vector<uint64_t>& box_sizes) -> std::shared_ptr<const MeshVariant> {
                                 constexpr uint64_t dimension = 1;
 
                                 if (box_sizes.size() != dimension) {
@@ -241,7 +223,7 @@ MeshModule::MeshModule()
                             std::function(
 
                               [](const TinyVector<2> a, const TinyVector<2> b,
-                                 const std::vector<uint64_t>& box_sizes) -> std::shared_ptr<const IMesh> {
+                                 const std::vector<uint64_t>& box_sizes) -> std::shared_ptr<const MeshVariant> {
                                 constexpr uint64_t dimension = 2;
 
                                 if (box_sizes.size() != dimension) {
@@ -267,7 +249,7 @@ MeshModule::MeshModule()
                             std::function(
 
                               [](const TinyVector<3>& a, const TinyVector<3>& b,
-                                 const std::vector<uint64_t>& box_sizes) -> std::shared_ptr<const IMesh> {
+                                 const std::vector<uint64_t>& box_sizes) -> std::shared_ptr<const MeshVariant> {
                                 constexpr uint64_t dimension = 3;
 
                                 if (box_sizes.size() != dimension) {
@@ -289,67 +271,23 @@ MeshModule::MeshModule()
 
                               ));
 
-  this->_addBuiltinFunction("diamondDual",
-                            std::function(
-
-                              [](const std::shared_ptr<const IMesh>& i_mesh) -> std::shared_ptr<const IMesh> {
-                                switch (i_mesh->dimension()) {
-                                case 1: {
-                                  using MeshType = Mesh<Connectivity<1>>;
-
-                                  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
-                                  return DualMeshManager::instance().getDiamondDualMesh(*p_mesh);
-                                }
-                                case 2: {
-                                  using MeshType = Mesh<Connectivity<2>>;
-
-                                  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
-                                  return DualMeshManager::instance().getDiamondDualMesh(*p_mesh);
-                                }
-                                case 3: {
-                                  using MeshType = Mesh<Connectivity<3>>;
-
-                                  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
-                                  return DualMeshManager::instance().getDiamondDualMesh(*p_mesh);
-                                }
-                                default: {
-                                  throw UnexpectedError("invalid dimension");
-                                }
-                                }
-                              }
-
-                              ));
-
-  this->_addBuiltinFunction("medianDual",
-                            std::function(
+  this->_addBuiltinFunction("diamondDual", std::function(
 
-                              [](const std::shared_ptr<const IMesh>& i_mesh) -> std::shared_ptr<const IMesh> {
-                                switch (i_mesh->dimension()) {
-                                case 1: {
-                                  using MeshType = Mesh<Connectivity<1>>;
+                                             [](const std::shared_ptr<const MeshVariant>& mesh_v)
+                                               -> std::shared_ptr<const MeshVariant> {
+                                               return DualMeshManager::instance().getDiamondDualMesh(mesh_v);
+                                             }
 
-                                  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
-                                  return DualMeshManager::instance().getMedianDualMesh(*p_mesh);
-                                }
-                                case 2: {
-                                  using MeshType = Mesh<Connectivity<2>>;
+                                             ));
 
-                                  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
-                                  return DualMeshManager::instance().getMedianDualMesh(*p_mesh);
-                                }
-                                case 3: {
-                                  using MeshType = Mesh<Connectivity<3>>;
+  this->_addBuiltinFunction("medianDual", std::function(
 
-                                  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
-                                  return DualMeshManager::instance().getMedianDualMesh(*p_mesh);
-                                }
-                                default: {
-                                  throw UnexpectedError("invalid dimension");
-                                }
-                                }
-                              }
+                                            [](const std::shared_ptr<const MeshVariant>& mesh_v)
+                                              -> std::shared_ptr<const MeshVariant> {
+                                              return DualMeshManager::instance().getMedianDualMesh(mesh_v);
+                                            }
 
-                              ));
+                                            ));
 }
 
 void
@@ -358,6 +296,7 @@ MeshModule::registerOperators() const
   OperatorRepository& repository = OperatorRepository::instance();
 
   repository.addBinaryOperator<language::shift_left_op>(
-    std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>,
-                                                    std::shared_ptr<const OStream>, std::shared_ptr<const IMesh>>>());
+    std::make_shared<
+      BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>,
+                                     std::shared_ptr<const OStream>, std::shared_ptr<const MeshVariant>>>());
 }
diff --git a/src/language/modules/MeshModule.hpp b/src/language/modules/MeshModule.hpp
index 0ea7e5762..10bfc9e1c 100644
--- a/src/language/modules/MeshModule.hpp
+++ b/src/language/modules/MeshModule.hpp
@@ -5,9 +5,9 @@
 #include <language/utils/ASTNodeDataTypeTraits.hpp>
 #include <utils/PugsMacros.hpp>
 
-class IMesh;
+class MeshVariant;
 template <>
-inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IMesh>> =
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const MeshVariant>> =
   ASTNodeDataType::build<ASTNodeDataType::type_id_t>("mesh");
 
 class IBoundaryDescriptor;
diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp
index 813bde93a..3736e8599 100644
--- a/src/language/modules/SchemeModule.cpp
+++ b/src/language/modules/SchemeModule.cpp
@@ -17,6 +17,7 @@
 #include <mesh/MeshDataManager.hpp>
 #include <mesh/MeshRandomizer.hpp>
 #include <mesh/MeshSmoother.hpp>
+#include <mesh/MeshTraits.hpp>
 #include <scheme/AcousticSolver.hpp>
 #include <scheme/AxisBoundaryConditionDescriptor.hpp>
 #include <scheme/DirichletBoundaryConditionDescriptor.hpp>
@@ -108,7 +109,7 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("integrate",
                             std::function(
 
-                              [](std::shared_ptr<const IMesh> mesh,
+                              [](std::shared_ptr<const MeshVariant> mesh,
                                  const std::vector<std::shared_ptr<const IZoneDescriptor>>& integration_zone_list,
                                  std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor,
                                  std::shared_ptr<const IDiscreteFunctionDescriptor> discrete_function_descriptor,
@@ -125,7 +126,7 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("integrate",
                             std::function(
 
-                              [](std::shared_ptr<const IMesh> mesh,
+                              [](std::shared_ptr<const MeshVariant> mesh,
                                  std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor,
                                  std::shared_ptr<const IDiscreteFunctionDescriptor> discrete_function_descriptor,
                                  const std::vector<FunctionSymbolId>& function_id_list)
@@ -141,7 +142,7 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("integrate",
                             std::function(
 
-                              [](std::shared_ptr<const IMesh> mesh,
+                              [](std::shared_ptr<const MeshVariant> mesh,
                                  const std::vector<std::shared_ptr<const IZoneDescriptor>>& integration_zone_list,
                                  std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor,
                                  const FunctionSymbolId& function_id)
@@ -157,7 +158,7 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("integrate",
                             std::function(
 
-                              [](std::shared_ptr<const IMesh> mesh,
+                              [](std::shared_ptr<const MeshVariant> mesh,
                                  std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor,
                                  const FunctionSymbolId& function_id)
                                 -> std::shared_ptr<const DiscreteFunctionVariant> {
@@ -170,7 +171,7 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("interpolate",
                             std::function(
 
-                              [](std::shared_ptr<const IMesh> mesh,
+                              [](std::shared_ptr<const MeshVariant> mesh,
                                  const std::vector<std::shared_ptr<const IZoneDescriptor>>& interpolation_zone_list,
                                  std::shared_ptr<const IDiscreteFunctionDescriptor> discrete_function_descriptor,
                                  const std::vector<FunctionSymbolId>& function_id_list)
@@ -202,7 +203,7 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("interpolate",
                             std::function(
 
-                              [](std::shared_ptr<const IMesh> mesh,
+                              [](std::shared_ptr<const MeshVariant> mesh,
                                  std::shared_ptr<const IDiscreteFunctionDescriptor> discrete_function_descriptor,
                                  const std::vector<FunctionSymbolId>& function_id_list)
                                 -> std::shared_ptr<const DiscreteFunctionVariant> {
@@ -232,11 +233,11 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("randomizeMesh",
                             std::function(
 
-                              [](std::shared_ptr<const IMesh> p_mesh,
+                              [](std::shared_ptr<const MeshVariant> mesh_v,
                                  const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
-                                   bc_descriptor_list) -> std::shared_ptr<const IMesh> {
+                                   bc_descriptor_list) -> std::shared_ptr<const MeshVariant> {
                                 MeshRandomizerHandler handler;
-                                return handler.getRandomizedMesh(*p_mesh, bc_descriptor_list);
+                                return handler.getRandomizedMesh(mesh_v, bc_descriptor_list);
                               }
 
                               ));
@@ -244,23 +245,23 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("randomizeMesh",
                             std::function(
 
-                              [](std::shared_ptr<const IMesh> p_mesh,
+                              [](std::shared_ptr<const MeshVariant> mesh_v,
                                  const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
                                    bc_descriptor_list,
-                                 const FunctionSymbolId& function_symbol_id) -> std::shared_ptr<const IMesh> {
+                                 const FunctionSymbolId& function_symbol_id) -> std::shared_ptr<const MeshVariant> {
                                 MeshRandomizerHandler handler;
-                                return handler.getRandomizedMesh(*p_mesh, bc_descriptor_list, function_symbol_id);
+                                return handler.getRandomizedMesh(mesh_v, bc_descriptor_list, function_symbol_id);
                               }
 
                               ));
 
   this->_addBuiltinFunction("smoothMesh", std::function(
 
-                                            [](std::shared_ptr<const IMesh> p_mesh,
+                                            [](std::shared_ptr<const MeshVariant> mesh_v,
                                                const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
-                                                 bc_descriptor_list) -> std::shared_ptr<const IMesh> {
+                                                 bc_descriptor_list) -> std::shared_ptr<const MeshVariant> {
                                               MeshSmootherHandler handler;
-                                              return handler.getSmoothedMesh(p_mesh, bc_descriptor_list);
+                                              return handler.getSmoothedMesh(mesh_v, bc_descriptor_list);
                                             }
 
                                             ));
@@ -268,12 +269,12 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("smoothMesh",
                             std::function(
 
-                              [](std::shared_ptr<const IMesh> p_mesh,
+                              [](std::shared_ptr<const MeshVariant> mesh_v,
                                  const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
                                    bc_descriptor_list,
-                                 const FunctionSymbolId& function_symbol_id) -> std::shared_ptr<const IMesh> {
+                                 const FunctionSymbolId& function_symbol_id) -> std::shared_ptr<const MeshVariant> {
                                 MeshSmootherHandler handler;
-                                return handler.getSmoothedMesh(p_mesh, bc_descriptor_list, function_symbol_id);
+                                return handler.getSmoothedMesh(mesh_v, bc_descriptor_list, function_symbol_id);
                               }
 
                               ));
@@ -281,26 +282,26 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("smoothMesh",
                             std::function(
 
-                              [](std::shared_ptr<const IMesh> p_mesh,
+                              [](std::shared_ptr<const MeshVariant> mesh_v,
                                  const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
                                    bc_descriptor_list,
                                  const std::vector<std::shared_ptr<const IZoneDescriptor>>& smoothing_zone_list)
-                                -> std::shared_ptr<const IMesh> {
+                                -> std::shared_ptr<const MeshVariant> {
                                 MeshSmootherHandler handler;
-                                return handler.getSmoothedMesh(p_mesh, bc_descriptor_list, smoothing_zone_list);
+                                return handler.getSmoothedMesh(mesh_v, bc_descriptor_list, smoothing_zone_list);
                               }
 
                               ));
 
   this->_addBuiltinFunction("smoothMesh", std::function(
 
-                                            [](std::shared_ptr<const IMesh> p_mesh,
+                                            [](std::shared_ptr<const MeshVariant> mesh_v,
                                                const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
                                                  bc_descriptor_list,
                                                const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>&
-                                                 discrete_function_variant_list) -> std::shared_ptr<const IMesh> {
+                                                 discrete_function_variant_list) -> std::shared_ptr<const MeshVariant> {
                                               MeshSmootherHandler handler;
-                                              return handler.getSmoothedMesh(p_mesh, bc_descriptor_list,
+                                              return handler.getSmoothedMesh(mesh_v, bc_descriptor_list,
                                                                              discrete_function_variant_list);
                                             }
 
@@ -429,7 +430,7 @@ SchemeModule::SchemeModule()
                                  const std::shared_ptr<const DiscreteFunctionVariant>& p,
                                  const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
                                    bc_descriptor_list,
-                                 const double& dt) -> std::tuple<std::shared_ptr<const IMesh>,
+                                 const double& dt) -> std::tuple<std::shared_ptr<const MeshVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>> {
@@ -470,7 +471,7 @@ SchemeModule::SchemeModule()
                                  const std::shared_ptr<const DiscreteFunctionVariant>& p,
                                  const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
                                    bc_descriptor_list,
-                                 const double& dt) -> std::tuple<std::shared_ptr<const IMesh>,
+                                 const double& dt) -> std::tuple<std::shared_ptr<const MeshVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>> {
@@ -490,7 +491,7 @@ SchemeModule::SchemeModule()
                                  const std::shared_ptr<const DiscreteFunctionVariant>& E,        //
                                  const std::shared_ptr<const ItemValueVariant>& ur,              //
                                  const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr,   //
-                                 const double& dt) -> std::tuple<std::shared_ptr<const IMesh>,
+                                 const double& dt) -> std::tuple<std::shared_ptr<const MeshVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>> {
@@ -533,7 +534,7 @@ SchemeModule::SchemeModule()
                                  const std::shared_ptr<const DiscreteFunctionVariant>& sigma,
                                  const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
                                    bc_descriptor_list,
-                                 const double& dt) -> std::tuple<std::shared_ptr<const IMesh>,
+                                 const double& dt) -> std::tuple<std::shared_ptr<const MeshVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
@@ -578,7 +579,7 @@ SchemeModule::SchemeModule()
                                  const std::shared_ptr<const DiscreteFunctionVariant>& sigma,
                                  const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
                                    bc_descriptor_list,
-                                 const double& dt) -> std::tuple<std::shared_ptr<const IMesh>,
+                                 const double& dt) -> std::tuple<std::shared_ptr<const MeshVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
@@ -600,7 +601,7 @@ SchemeModule::SchemeModule()
                                  const std::shared_ptr<const DiscreteFunctionVariant>& CG,       //
                                  const std::shared_ptr<const ItemValueVariant>& ur,              //
                                  const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr,   //
-                                 const double& dt) -> std::tuple<std::shared_ptr<const IMesh>,
+                                 const double& dt) -> std::tuple<std::shared_ptr<const MeshVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
                                                                  std::shared_ptr<const DiscreteFunctionVariant>,
@@ -615,7 +616,7 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("lagrangian",
                             std::function(
 
-                              [](const std::shared_ptr<const IMesh>& mesh,
+                              [](const std::shared_ptr<const MeshVariant>& mesh,
                                  const std::shared_ptr<const DiscreteFunctionVariant>& v)
                                 -> std::shared_ptr<const DiscreteFunctionVariant> { return shallowCopy(mesh, v); }
 
@@ -632,40 +633,19 @@ SchemeModule::SchemeModule()
   this->_addBuiltinFunction("cell_volume",
                             std::function(
 
-                              [](const std::shared_ptr<const IMesh>& i_mesh)
+                              [](const std::shared_ptr<const MeshVariant>& i_mesh)
                                 -> std::shared_ptr<const DiscreteFunctionVariant> {
-                                switch (i_mesh->dimension()) {
-                                case 1: {
-                                  constexpr size_t Dimension = 1;
-                                  using MeshType             = Mesh<Connectivity<Dimension>>;
-                                  std::shared_ptr<const MeshType> mesh =
-                                    std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh);
-
-                                  return std::make_shared<DiscreteFunctionVariant>(
-                                    DiscreteFunctionP0(mesh, MeshDataManager::instance().getMeshData(*mesh).Vj()));
-                                }
-                                case 2: {
-                                  constexpr size_t Dimension = 2;
-                                  using MeshType             = Mesh<Connectivity<Dimension>>;
-                                  std::shared_ptr<const MeshType> mesh =
-                                    std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh);
-
-                                  return std::make_shared<DiscreteFunctionVariant>(
-                                    DiscreteFunctionP0(mesh, MeshDataManager::instance().getMeshData(*mesh).Vj()));
-                                }
-                                case 3: {
-                                  constexpr size_t Dimension = 3;
-                                  using MeshType             = Mesh<Connectivity<Dimension>>;
-                                  std::shared_ptr<const MeshType> mesh =
-                                    std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh);
-
-                                  return std::make_shared<DiscreteFunctionVariant>(
-                                    DiscreteFunctionP0(mesh, MeshDataManager::instance().getMeshData(*mesh).Vj()));
-                                }
-                                default: {
-                                  throw UnexpectedError("invalid mesh dimension");
-                                }
-                                }
+                                return std::visit(
+                                  [](auto&& mesh) {
+                                    using MeshType = typename std::decay_t<decltype(mesh)>::element_type;
+                                    if constexpr (is_polygonal_mesh<MeshType>) {
+                                      return std::make_shared<DiscreteFunctionVariant>(
+                                        DiscreteFunctionP0(mesh, MeshDataManager::instance().getMeshData(*mesh).Vj()));
+                                    } else {
+                                      throw NormalError("unexpected mesh type");
+                                    }
+                                  },
+                                  i_mesh->meshPointer());
                               }
 
                               ));
@@ -680,7 +660,7 @@ SchemeModule::SchemeModule()
 
   this->_addBuiltinFunction("fluxing_advection", std::function(
 
-                                                   [](const std::shared_ptr<const IMesh> new_mesh,
+                                                   [](const std::shared_ptr<const MeshVariant> new_mesh,
                                                       const std::vector<std::shared_ptr<const VariableBCDescriptor>>&
                                                         remapped_quantity_with_bc)
                                                      -> std::vector<std::shared_ptr<const DiscreteFunctionVariant>> {
diff --git a/src/language/modules/WriterModule.cpp b/src/language/modules/WriterModule.cpp
index af7d0cb4b..fc9d5703e 100644
--- a/src/language/modules/WriterModule.cpp
+++ b/src/language/modules/WriterModule.cpp
@@ -106,9 +106,8 @@ WriterModule::WriterModule()
   this->_addBuiltinFunction("write_mesh",
                             std::function(
 
-                              [](std::shared_ptr<const IWriter> writer, std::shared_ptr<const IMesh> p_mesh) -> void {
-                                writer->writeMesh(p_mesh);
-                              }
+                              [](std::shared_ptr<const IWriter> writer,
+                                 std::shared_ptr<const MeshVariant> mesh_v) -> void { writer->writeMesh(mesh_v); }
 
                               ));
 
@@ -144,35 +143,37 @@ WriterModule::WriterModule()
 
                                              ));
 
-  this->_addBuiltinFunction("write", std::function(
+  this->_addBuiltinFunction("write",
+                            std::function(
 
-                                       [](std::shared_ptr<const IWriter> writer, std::shared_ptr<const IMesh> mesh,
-                                          const std::vector<std::shared_ptr<const INamedDiscreteData>>&
-                                            named_discrete_function_list) -> void {
-                                         writer->writeOnMesh(mesh, named_discrete_function_list);
-                                       }
+                              [](std::shared_ptr<const IWriter> writer, std::shared_ptr<const MeshVariant> mesh_v,
+                                 const std::vector<std::shared_ptr<const INamedDiscreteData>>&
+                                   named_discrete_function_list) -> void {
+                                writer->writeOnMesh(mesh_v, named_discrete_function_list);
+                              }
 
-                                       ));
+                              ));
 
-  this->_addBuiltinFunction("write", std::function(
+  this->_addBuiltinFunction("write",
+                            std::function(
 
-                                       [](std::shared_ptr<const IWriter> writer, std::shared_ptr<const IMesh> mesh,
-                                          const std::vector<std::shared_ptr<const INamedDiscreteData>>&
-                                            named_discrete_function_list,
-                                          const double& time) -> void {
-                                         writer->writeOnMeshIfNeeded(mesh, named_discrete_function_list, time);
-                                       }
+                              [](std::shared_ptr<const IWriter> writer, std::shared_ptr<const MeshVariant> mesh_v,
+                                 const std::vector<std::shared_ptr<const INamedDiscreteData>>&
+                                   named_discrete_function_list,
+                                 const double& time) -> void {
+                                writer->writeOnMeshIfNeeded(mesh_v, named_discrete_function_list, time);
+                              }
 
-                                       ));
+                              ));
 
   this->_addBuiltinFunction("force_write",
                             std::function(
 
-                              [](std::shared_ptr<const IWriter> writer, std::shared_ptr<const IMesh> mesh,
+                              [](std::shared_ptr<const IWriter> writer, std::shared_ptr<const MeshVariant> mesh_v,
                                  const std::vector<std::shared_ptr<const INamedDiscreteData>>&
                                    named_discrete_function_list,
                                  const double& time) -> void {
-                                writer->writeOnMeshForced(mesh, named_discrete_function_list, time);
+                                writer->writeOnMeshForced(mesh_v, named_discrete_function_list, time);
                               }
 
                               ));
diff --git a/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.cpp b/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.cpp
index 0f9224fed..eb7cebd57 100644
--- a/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.cpp
+++ b/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.cpp
@@ -1,7 +1,7 @@
 #include <language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp>
 
 #include <language/utils/EmbeddedDiscreteFunctionUtils.hpp>
-#include <mesh/IMesh.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <scheme/DiscreteFunctionP0.hpp>
 #include <scheme/DiscreteFunctionP0Vector.hpp>
 #include <scheme/DiscreteFunctionUtils.hpp>
@@ -546,49 +546,22 @@ std::shared_ptr<const DiscreteFunctionVariant>
 vectorize(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_list)
 {
   if (hasSameMesh(discrete_function_list)) {
-    std::shared_ptr p_i_mesh = getCommonMesh(discrete_function_list);
-    Assert(p_i_mesh.use_count() > 0);
+    std::shared_ptr mesh_v = getCommonMesh(discrete_function_list);
+    Assert(mesh_v.use_count() > 0);
 
-    switch (p_i_mesh->dimension()) {
-    case 1: {
-      constexpr size_t Dimension       = 1;
-      using DiscreteFunctionVectorType = DiscreteFunctionP0Vector<Dimension, double>;
-      std::shared_ptr<const Mesh<Connectivity<Dimension>>> p_mesh =
-        std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(p_i_mesh);
+    return std::visit(
+      [&](auto&& mesh) {
+        using MeshType                   = typename std::decay_t<decltype(mesh)>::element_type;
+        constexpr size_t Dimension       = MeshType::Dimension;
+        using DiscreteFunctionVectorType = DiscreteFunctionP0Vector<Dimension, double>;
 
-      DiscreteFunctionVectorType vector_function(p_mesh, discrete_function_list.size());
-      vectorize_to(discrete_function_list, *p_mesh, vector_function);
+        DiscreteFunctionVectorType vector_function(mesh, discrete_function_list.size());
+        vectorize_to(discrete_function_list, *mesh, vector_function);
 
-      return std::make_shared<DiscreteFunctionVariant>(vector_function);
-    }
-    case 2: {
-      constexpr size_t Dimension       = 2;
-      using DiscreteFunctionVectorType = DiscreteFunctionP0Vector<Dimension, double>;
-      std::shared_ptr<const Mesh<Connectivity<Dimension>>> p_mesh =
-        std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(p_i_mesh);
-
-      DiscreteFunctionVectorType vector_function(p_mesh, discrete_function_list.size());
-      vectorize_to(discrete_function_list, *p_mesh, vector_function);
-
-      return std::make_shared<DiscreteFunctionVariant>(vector_function);
-    }
-    case 3: {
-      constexpr size_t Dimension       = 3;
-      using DiscreteFunctionVectorType = DiscreteFunctionP0Vector<Dimension, double>;
-      std::shared_ptr<const Mesh<Connectivity<Dimension>>> p_mesh =
-        std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(p_i_mesh);
+        return std::make_shared<DiscreteFunctionVariant>(vector_function);
+      },
+      mesh_v->meshPointer());
 
-      DiscreteFunctionVectorType vector_function(p_mesh, discrete_function_list.size());
-      vectorize_to(discrete_function_list, *p_mesh, vector_function);
-
-      return std::make_shared<DiscreteFunctionVariant>(vector_function);
-    }
-      // LCOV_EXCL_START
-    default: {
-      throw UnexpectedError("invalid mesh dimension");
-    }
-      // LCOV_EXCL_STOP
-    }
   } else {
     throw NormalError("discrete functions are not defined on the same mesh");
   }
diff --git a/src/language/utils/IntegrateCellValue.hpp b/src/language/utils/IntegrateCellValue.hpp
index cd8bacc07..5c2e357aa 100644
--- a/src/language/utils/IntegrateCellValue.hpp
+++ b/src/language/utils/IntegrateCellValue.hpp
@@ -6,6 +6,8 @@
 #include <mesh/ItemType.hpp>
 #include <mesh/ItemValue.hpp>
 #include <mesh/Mesh.hpp>
+#include <mesh/MeshTraits.hpp>
+#include <mesh/MeshVariant.hpp>
 
 template <typename T>
 class IntegrateCellValue;
@@ -19,6 +21,7 @@ class IntegrateCellValue<OutputType(InputType)>
             const IQuadratureDescriptor& quadrature_descriptor,
             const MeshType& mesh)
   {
+    static_assert(is_polygonal_mesh<MeshType>);
     CellValue<OutputType> value(mesh.connectivity());
     IntegrateOnCells<OutputType(const InputType)>::template integrateTo<MeshType>(function_symbol_id,
                                                                                   quadrature_descriptor, mesh, value);
@@ -26,6 +29,23 @@ class IntegrateCellValue<OutputType(InputType)>
     return value;
   }
 
+  PUGS_INLINE static CellValue<OutputType>
+  integrate(const FunctionSymbolId& function_symbol_id,
+            const IQuadratureDescriptor& quadrature_descriptor,
+            const std::shared_ptr<const MeshVariant>& mesh_v)
+  {
+    return std::visit(
+      [&](auto&& p_mesh) -> CellValue<OutputType> {
+        using MeshType = typename std::decay_t<decltype(p_mesh)>::element_type;
+        if constexpr ((is_polygonal_mesh<MeshType>)and(MeshType::Dimension == InputType::Dimension)) {
+          return integrate(function_symbol_id, quadrature_descriptor, *p_mesh);
+        } else {
+          throw NormalError("invalid mesh type");
+        }
+      },
+      mesh_v->meshPointer());
+  }
+
   template <typename MeshType>
   PUGS_INLINE static Array<OutputType>
   integrate(const FunctionSymbolId& function_symbol_id,
@@ -33,10 +53,29 @@ class IntegrateCellValue<OutputType(InputType)>
             const MeshType& mesh,
             const Array<const CellId>& list_of_cells)
   {
+    static_assert(is_polygonal_mesh<MeshType>);
     return IntegrateOnCells<OutputType(const InputType)>::integrate(function_symbol_id, quadrature_descriptor, mesh,
                                                                     Array<const CellId>{list_of_cells});
   }
 
+  PUGS_INLINE static Array<OutputType>
+  integrate(const FunctionSymbolId& function_symbol_id,
+            const IQuadratureDescriptor& quadrature_descriptor,
+            const std::shared_ptr<const MeshVariant>& mesh_v,
+            const Array<const CellId>& list_of_cells)
+  {
+    return std::visit(
+      [&](auto&& p_mesh) -> Array<OutputType> {
+        using MeshType = typename std::decay_t<decltype(p_mesh)>::element_type;
+        if constexpr ((is_polygonal_mesh<MeshType>)and(MeshType::Dimension == InputType::Dimension)) {
+          return integrate(function_symbol_id, quadrature_descriptor, *p_mesh, list_of_cells);
+        } else {
+          throw NormalError("invalid mesh type");
+        }
+      },
+      mesh_v->meshPointer());
+  }
+
   template <typename MeshType>
   PUGS_INLINE static Array<OutputType>
   integrate(const FunctionSymbolId& function_symbol_id,
@@ -44,8 +83,27 @@ class IntegrateCellValue<OutputType(InputType)>
             const MeshType& mesh,
             const Array<CellId>& list_of_cells)
   {
+    static_assert(is_polygonal_mesh<MeshType>);
     return integrate(function_symbol_id, quadrature_descriptor, mesh, Array<const CellId>{list_of_cells});
   }
+
+  PUGS_INLINE static Array<OutputType>
+  integrate(const FunctionSymbolId& function_symbol_id,
+            const IQuadratureDescriptor& quadrature_descriptor,
+            const std::shared_ptr<const MeshVariant>& mesh_v,
+            const Array<CellId>& list_of_cells)
+  {
+    return std::visit(
+      [&](auto&& p_mesh) -> Array<OutputType> {
+        using MeshType = typename std::decay_t<decltype(p_mesh)>::element_type;
+        if constexpr ((is_polygonal_mesh<MeshType>)and(MeshType::Dimension == InputType::Dimension)) {
+          return integrate(function_symbol_id, quadrature_descriptor, *p_mesh, list_of_cells);
+        } else {
+          throw NormalError("invalid mesh type");
+        }
+      },
+      mesh_v->meshPointer());
+  }
 };
 
 #endif   // INTEGRATE_CELL_VALUE_HPP
diff --git a/src/language/utils/ItemArrayVariantFunctionInterpoler.cpp b/src/language/utils/ItemArrayVariantFunctionInterpoler.cpp
index 2ed94cbff..86bbf0851 100644
--- a/src/language/utils/ItemArrayVariantFunctionInterpoler.cpp
+++ b/src/language/utils/ItemArrayVariantFunctionInterpoler.cpp
@@ -6,16 +6,19 @@
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshData.hpp>
 #include <mesh/MeshDataManager.hpp>
+#include <mesh/MeshTraits.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <utils/Exceptions.hpp>
 
 #include <memory>
 
-template <size_t Dimension, typename DataType, typename ArrayType>
+template <typename MeshType, typename DataType>
 std::shared_ptr<ItemArrayVariant>
 ItemArrayVariantFunctionInterpoler::_interpolate() const
 {
-  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(m_mesh);
-  using MeshDataType     = MeshData<Dimension>;
+  std::shared_ptr p_mesh     = m_mesh_v->get<MeshType>();
+  constexpr size_t Dimension = MeshType::Dimension;
+  using MeshDataType         = MeshData<Dimension>;
 
   switch (m_item_type) {
   case ItemType::cell: {
@@ -49,7 +52,7 @@ ItemArrayVariantFunctionInterpoler::_interpolate() const
   }
 }
 
-template <size_t Dimension>
+template <typename MeshType>
 std::shared_ptr<ItemArrayVariant>
 ItemArrayVariantFunctionInterpoler::_interpolate() const
 {
@@ -74,27 +77,27 @@ ItemArrayVariantFunctionInterpoler::_interpolate() const
 
   switch (data_type) {
   case ASTNodeDataType::bool_t: {
-    return this->_interpolate<Dimension, bool>();
+    return this->_interpolate<MeshType, bool>();
   }
   case ASTNodeDataType::unsigned_int_t: {
-    return this->_interpolate<Dimension, uint64_t>();
+    return this->_interpolate<MeshType, uint64_t>();
   }
   case ASTNodeDataType::int_t: {
-    return this->_interpolate<Dimension, int64_t>();
+    return this->_interpolate<MeshType, int64_t>();
   }
   case ASTNodeDataType::double_t: {
-    return this->_interpolate<Dimension, double>();
+    return this->_interpolate<MeshType, double>();
   }
   case ASTNodeDataType::vector_t: {
     switch (data_type.dimension()) {
     case 1: {
-      return this->_interpolate<Dimension, TinyVector<1>>();
+      return this->_interpolate<MeshType, TinyVector<1>>();
     }
     case 2: {
-      return this->_interpolate<Dimension, TinyVector<2>>();
+      return this->_interpolate<MeshType, TinyVector<2>>();
     }
     case 3: {
-      return this->_interpolate<Dimension, TinyVector<3>>();
+      return this->_interpolate<MeshType, TinyVector<3>>();
     }
       // LCOV_EXCL_START
     default: {
@@ -110,13 +113,13 @@ ItemArrayVariantFunctionInterpoler::_interpolate() const
     Assert(data_type.numberOfColumns() == data_type.numberOfRows(), "undefined matrix type");
     switch (data_type.numberOfColumns()) {
     case 1: {
-      return this->_interpolate<Dimension, TinyMatrix<1>>();
+      return this->_interpolate<MeshType, TinyMatrix<1>>();
     }
     case 2: {
-      return this->_interpolate<Dimension, TinyMatrix<2>>();
+      return this->_interpolate<MeshType, TinyMatrix<2>>();
     }
     case 3: {
-      return this->_interpolate<Dimension, TinyMatrix<3>>();
+      return this->_interpolate<MeshType, TinyMatrix<3>>();
     }
       // LCOV_EXCL_START
     default: {
@@ -142,20 +145,14 @@ ItemArrayVariantFunctionInterpoler::_interpolate() const
 std::shared_ptr<ItemArrayVariant>
 ItemArrayVariantFunctionInterpoler::interpolate() const
 {
-  switch (m_mesh->dimension()) {
-  case 1: {
-    return this->_interpolate<1>();
-  }
-  case 2: {
-    return this->_interpolate<2>();
-  }
-  case 3: {
-    return this->_interpolate<3>();
-  }
-    // LCOV_EXCL_START
-  default: {
-    throw UnexpectedError("invalid dimension");
-  }
-    // LCOV_EXCL_STOP
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      using MeshType = typename std::decay_t<decltype(mesh)>::element_type;
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        return this->_interpolate<MeshType>();
+      } else {
+        throw UnexpectedError("invalid mesh type");
+      }
+    },
+    m_mesh_v->meshPointer());
 }
diff --git a/src/language/utils/ItemArrayVariantFunctionInterpoler.hpp b/src/language/utils/ItemArrayVariantFunctionInterpoler.hpp
index eac61b5fb..8631212dc 100644
--- a/src/language/utils/ItemArrayVariantFunctionInterpoler.hpp
+++ b/src/language/utils/ItemArrayVariantFunctionInterpoler.hpp
@@ -2,31 +2,32 @@
 #define ITEM_ARRAY_VARIANT_FUNCTION_INTERPOLER_HPP
 
 #include <language/utils/FunctionSymbolId.hpp>
-#include <mesh/IMesh.hpp>
 #include <mesh/IZoneDescriptor.hpp>
 #include <mesh/ItemArrayVariant.hpp>
 #include <mesh/ItemType.hpp>
 
+class MeshVariant;
+
 class ItemArrayVariantFunctionInterpoler
 {
  private:
-  std::shared_ptr<const IMesh> m_mesh;
+  std::shared_ptr<const MeshVariant> m_mesh_v;
   const ItemType m_item_type;
   const std::vector<FunctionSymbolId> m_function_id_list;
 
-  template <size_t Dimension, typename DataType, typename ArrayType = DataType>
+  template <typename MeshType, typename DataType>
   std::shared_ptr<ItemArrayVariant> _interpolate() const;
 
-  template <size_t Dimension>
+  template <typename MeshType>
   std::shared_ptr<ItemArrayVariant> _interpolate() const;
 
  public:
   std::shared_ptr<ItemArrayVariant> interpolate() const;
 
-  ItemArrayVariantFunctionInterpoler(const std::shared_ptr<const IMesh>& mesh,
+  ItemArrayVariantFunctionInterpoler(const std::shared_ptr<const MeshVariant>& mesh_v,
                                      const ItemType& item_type,
                                      const std::vector<FunctionSymbolId>& function_id_list)
-    : m_mesh{mesh}, m_item_type{item_type}, m_function_id_list{function_id_list}
+    : m_mesh_v{mesh_v}, m_item_type{item_type}, m_function_id_list{function_id_list}
   {}
 
   ItemArrayVariantFunctionInterpoler(const ItemArrayVariantFunctionInterpoler&) = delete;
diff --git a/src/language/utils/ItemValueVariantFunctionInterpoler.cpp b/src/language/utils/ItemValueVariantFunctionInterpoler.cpp
index 98dbe1658..bb3d5ad2b 100644
--- a/src/language/utils/ItemValueVariantFunctionInterpoler.cpp
+++ b/src/language/utils/ItemValueVariantFunctionInterpoler.cpp
@@ -6,16 +6,19 @@
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshData.hpp>
 #include <mesh/MeshDataManager.hpp>
+#include <mesh/MeshTraits.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <utils/Exceptions.hpp>
 
 #include <memory>
 
-template <size_t Dimension, typename DataType, typename ValueType>
+template <typename MeshType, typename DataType>
 std::shared_ptr<ItemValueVariant>
 ItemValueVariantFunctionInterpoler::_interpolate() const
 {
-  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(m_mesh);
-  using MeshDataType     = MeshData<Dimension>;
+  std::shared_ptr p_mesh     = m_mesh_v->get<MeshType>();
+  constexpr size_t Dimension = MeshType::Dimension;
+  using MeshDataType         = MeshData<Dimension>;
 
   switch (m_item_type) {
   case ItemType::cell: {
@@ -49,7 +52,7 @@ ItemValueVariantFunctionInterpoler::_interpolate() const
   }
 }
 
-template <size_t Dimension>
+template <typename MeshType>
 std::shared_ptr<ItemValueVariant>
 ItemValueVariantFunctionInterpoler::_interpolate() const
 {
@@ -60,27 +63,27 @@ ItemValueVariantFunctionInterpoler::_interpolate() const
 
   switch (data_type) {
   case ASTNodeDataType::bool_t: {
-    return this->_interpolate<Dimension, bool>();
+    return this->_interpolate<MeshType, bool>();
   }
   case ASTNodeDataType::unsigned_int_t: {
-    return this->_interpolate<Dimension, uint64_t>();
+    return this->_interpolate<MeshType, uint64_t>();
   }
   case ASTNodeDataType::int_t: {
-    return this->_interpolate<Dimension, int64_t>();
+    return this->_interpolate<MeshType, int64_t>();
   }
   case ASTNodeDataType::double_t: {
-    return this->_interpolate<Dimension, double>();
+    return this->_interpolate<MeshType, double>();
   }
   case ASTNodeDataType::vector_t: {
     switch (data_type.dimension()) {
     case 1: {
-      return this->_interpolate<Dimension, TinyVector<1>>();
+      return this->_interpolate<MeshType, TinyVector<1>>();
     }
     case 2: {
-      return this->_interpolate<Dimension, TinyVector<2>>();
+      return this->_interpolate<MeshType, TinyVector<2>>();
     }
     case 3: {
-      return this->_interpolate<Dimension, TinyVector<3>>();
+      return this->_interpolate<MeshType, TinyVector<3>>();
     }
       // LCOV_EXCL_START
     default: {
@@ -96,13 +99,13 @@ ItemValueVariantFunctionInterpoler::_interpolate() const
     Assert(data_type.numberOfColumns() == data_type.numberOfRows(), "undefined matrix type");
     switch (data_type.numberOfColumns()) {
     case 1: {
-      return this->_interpolate<Dimension, TinyMatrix<1>>();
+      return this->_interpolate<MeshType, TinyMatrix<1>>();
     }
     case 2: {
-      return this->_interpolate<Dimension, TinyMatrix<2>>();
+      return this->_interpolate<MeshType, TinyMatrix<2>>();
     }
     case 3: {
-      return this->_interpolate<Dimension, TinyMatrix<3>>();
+      return this->_interpolate<MeshType, TinyMatrix<3>>();
     }
       // LCOV_EXCL_START
     default: {
@@ -128,20 +131,14 @@ ItemValueVariantFunctionInterpoler::_interpolate() const
 std::shared_ptr<ItemValueVariant>
 ItemValueVariantFunctionInterpoler::interpolate() const
 {
-  switch (m_mesh->dimension()) {
-  case 1: {
-    return this->_interpolate<1>();
-  }
-  case 2: {
-    return this->_interpolate<2>();
-  }
-  case 3: {
-    return this->_interpolate<3>();
-  }
-    // LCOV_EXCL_START
-  default: {
-    throw UnexpectedError("invalid dimension");
-  }
-    // LCOV_EXCL_STOP
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      using MeshType = typename std::decay_t<decltype(mesh)>::element_type;
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        return this->_interpolate<MeshType>();
+      } else {
+        throw UnexpectedError("invalid mesh type");
+      }
+    },
+    m_mesh_v->meshPointer());
 }
diff --git a/src/language/utils/ItemValueVariantFunctionInterpoler.hpp b/src/language/utils/ItemValueVariantFunctionInterpoler.hpp
index 4e03f72fc..c1c4daddd 100644
--- a/src/language/utils/ItemValueVariantFunctionInterpoler.hpp
+++ b/src/language/utils/ItemValueVariantFunctionInterpoler.hpp
@@ -2,31 +2,32 @@
 #define ITEM_VALUE_VARIANT_FUNCTION_INTERPOLER_HPP
 
 #include <language/utils/FunctionSymbolId.hpp>
-#include <mesh/IMesh.hpp>
 #include <mesh/IZoneDescriptor.hpp>
 #include <mesh/ItemType.hpp>
 #include <mesh/ItemValueVariant.hpp>
 
+class MeshVariant;
+
 class ItemValueVariantFunctionInterpoler
 {
  private:
-  std::shared_ptr<const IMesh> m_mesh;
+  std::shared_ptr<const MeshVariant> m_mesh_v;
   const ItemType m_item_type;
   const FunctionSymbolId m_function_id;
 
-  template <size_t Dimension, typename DataType, typename ValueType = DataType>
+  template <typename MeshType, typename DataType>
   std::shared_ptr<ItemValueVariant> _interpolate() const;
 
-  template <size_t Dimension>
+  template <typename MeshType>
   std::shared_ptr<ItemValueVariant> _interpolate() const;
 
  public:
   std::shared_ptr<ItemValueVariant> interpolate() const;
 
-  ItemValueVariantFunctionInterpoler(const std::shared_ptr<const IMesh>& mesh,
+  ItemValueVariantFunctionInterpoler(const std::shared_ptr<const MeshVariant>& mesh_v,
                                      const ItemType& item_type,
                                      const FunctionSymbolId& function_id)
-    : m_mesh{mesh}, m_item_type{item_type}, m_function_id{function_id}
+    : m_mesh_v{mesh_v}, m_item_type{item_type}, m_function_id{function_id}
   {}
 
   ItemValueVariantFunctionInterpoler(const ItemValueVariantFunctionInterpoler&) = delete;
diff --git a/src/mesh/CMakeLists.txt b/src/mesh/CMakeLists.txt
index 9b82b62f1..99d9680a5 100644
--- a/src/mesh/CMakeLists.txt
+++ b/src/mesh/CMakeLists.txt
@@ -16,10 +16,10 @@ add_library(
   DualMeshManager.cpp
   GmshReader.cpp
   IConnectivity.cpp
-  IMesh.cpp
   LogicalConnectivityBuilder.cpp
   MedianDualConnectivityBuilder.cpp
   MedianDualMeshBuilder.cpp
+  Mesh.cpp
   MeshBuilderBase.cpp
   MeshCellZone.cpp
   MeshData.cpp
@@ -31,15 +31,17 @@ add_library(
   MeshFlatEdgeBoundary.cpp
   MeshFlatFaceBoundary.cpp
   MeshFlatNodeBoundary.cpp
-  MeshRelaxer.cpp
   MeshLineEdgeBoundary.cpp
   MeshLineFaceBoundary.cpp
   MeshLineNodeBoundary.cpp
   MeshNodeBoundary.cpp
   MeshNodeInterface.cpp
   MeshRandomizer.cpp
+  MeshRelaxer.cpp
   MeshSmoother.cpp
   MeshTransformer.cpp
+  MeshUtils.cpp
+  MeshVariant.cpp
   SynchronizerManager.cpp
 )
 
diff --git a/src/mesh/CartesianMeshBuilder.cpp b/src/mesh/CartesianMeshBuilder.cpp
index 226ff751f..7b98ea861 100644
--- a/src/mesh/CartesianMeshBuilder.cpp
+++ b/src/mesh/CartesianMeshBuilder.cpp
@@ -2,6 +2,7 @@
 
 #include <mesh/Connectivity.hpp>
 #include <mesh/LogicalConnectivityBuilder.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <utils/Array.hpp>
 #include <utils/Messenger.hpp>
 
@@ -116,7 +117,7 @@ CartesianMeshBuilder::_buildCartesianMesh(const TinyVector<Dimension>& a,
 
   NodeValue<TinyVector<Dimension>> xr = _getNodeCoordinates(a, b, cell_size, connectivity);
 
-  m_mesh = std::make_shared<Mesh<ConnectivityType>>(p_connectivity, xr);
+  m_mesh = std::make_shared<MeshVariant>(std::make_shared<const Mesh<ConnectivityType>>(p_connectivity, xr));
 }
 
 template <size_t Dimension>
diff --git a/src/mesh/DiamondDualMeshBuilder.cpp b/src/mesh/DiamondDualMeshBuilder.cpp
index 64711edc7..c591ca59a 100644
--- a/src/mesh/DiamondDualMeshBuilder.cpp
+++ b/src/mesh/DiamondDualMeshBuilder.cpp
@@ -6,19 +6,19 @@
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshData.hpp>
 #include <mesh/MeshDataManager.hpp>
+#include <mesh/MeshTraits.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <mesh/PrimalToDiamondDualConnectivityDataMapper.hpp>
 #include <utils/Stringify.hpp>
 
-template <size_t Dimension>
+template <typename MeshType>
 void
-DiamondDualMeshBuilder::_buildDualDiamondMeshFrom(const IMesh& i_mesh)
+DiamondDualMeshBuilder::_buildDualDiamondMeshFrom(const MeshType& primal_mesh)
 {
-  static_assert(Dimension > 1);
-
-  using ConnectivityType = Connectivity<Dimension>;
-  using MeshType         = Mesh<Connectivity<Dimension>>;
+  constexpr size_t Dimension = MeshType::Dimension;
+  using ConnectivityType     = typename MeshType::Connectivity;
 
-  const MeshType& primal_mesh = dynamic_cast<const MeshType&>(i_mesh);
+  static_assert(Dimension > 1);
 
   DualConnectivityManager& manager = DualConnectivityManager::instance();
 
@@ -38,24 +38,23 @@ DiamondDualMeshBuilder::_buildDualDiamondMeshFrom(const IMesh& i_mesh)
   NodeValue<TinyVector<Dimension>> diamond_xr{diamond_connectivity};
   primal_to_diamond_dual_connectivity_data_mapper->toDualNode(primal_xr, primal_xj, diamond_xr);
 
-  m_mesh = std::make_shared<MeshType>(p_diamond_connectivity, diamond_xr);
+  m_mesh = std::make_shared<MeshVariant>(std::make_shared<const MeshType>(p_diamond_connectivity, diamond_xr));
 }
 
-DiamondDualMeshBuilder::DiamondDualMeshBuilder(const IMesh& i_mesh)
+DiamondDualMeshBuilder::DiamondDualMeshBuilder(const std::shared_ptr<const MeshVariant>& mesh_v)
 {
-  switch (i_mesh.dimension()) {
-  case 2: {
-    this->_buildDualDiamondMeshFrom<2>(i_mesh);
-    break;
-  }
-  case 3: {
-    this->_buildDualDiamondMeshFrom<3>(i_mesh);
-    break;
-  }
-    // LCOV_EXCL_START
-  default: {
-    throw UnexpectedError("invalid mesh dimension: " + stringify(i_mesh.dimension()));
-  }
-    // LCOV_EXCL_STOP
-  }
+  std::visit(
+    [&](auto&& p_mesh) {
+      using MeshType = std::decay_t<decltype(p_mesh)>::element_type;
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        if constexpr (MeshType::Dimension > 1) {
+          this->_buildDualDiamondMeshFrom(*p_mesh);
+        } else {
+          throw UnexpectedError("invalid polygonal mesh dimension");
+        }
+      } else {
+        throw UnexpectedError("invalid mesh type");
+      }
+    },
+    mesh_v->meshPointer());
 }
diff --git a/src/mesh/DiamondDualMeshBuilder.hpp b/src/mesh/DiamondDualMeshBuilder.hpp
index 1dc670638..d1c2b6dbd 100644
--- a/src/mesh/DiamondDualMeshBuilder.hpp
+++ b/src/mesh/DiamondDualMeshBuilder.hpp
@@ -3,16 +3,15 @@
 
 #include <mesh/MeshBuilderBase.hpp>
 
-#include <memory>
-
+class MeshVariant;
 class DiamondDualMeshBuilder : public MeshBuilderBase
 {
  private:
-  template <size_t Dimension>
-  void _buildDualDiamondMeshFrom(const IMesh&);
+  template <typename MeshType>
+  void _buildDualDiamondMeshFrom(const MeshType&);
 
   friend class DualMeshManager;
-  DiamondDualMeshBuilder(const IMesh&);
+  DiamondDualMeshBuilder(const std::shared_ptr<const MeshVariant>&);
 
  public:
   ~DiamondDualMeshBuilder() = default;
diff --git a/src/mesh/Dual1DMeshBuilder.cpp b/src/mesh/Dual1DMeshBuilder.cpp
index db47aa6d4..c2d0f6342 100644
--- a/src/mesh/Dual1DMeshBuilder.cpp
+++ b/src/mesh/Dual1DMeshBuilder.cpp
@@ -6,17 +6,20 @@
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshData.hpp>
 #include <mesh/MeshDataManager.hpp>
+#include <mesh/MeshTraits.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <mesh/PrimalToDiamondDualConnectivityDataMapper.hpp>
 #include <mesh/PrimalToDual1DConnectivityDataMapper.hpp>
 #include <utils/Stringify.hpp>
 
+template <typename MeshType>
 void
-Dual1DMeshBuilder::_buildDual1DMeshFrom(const IMesh& i_mesh)
+Dual1DMeshBuilder::_buildDual1DMeshFrom(const MeshType& primal_mesh)
 {
-  using ConnectivityType = Connectivity<1>;
-  using MeshType         = Mesh<Connectivity<1>>;
+  static_assert(is_polygonal_mesh<MeshType>);
+  static_assert(MeshType::Dimension == 1);
 
-  const MeshType& primal_mesh = dynamic_cast<const MeshType&>(i_mesh);
+  using ConnectivityType = typename MeshType::Connectivity;
 
   DualConnectivityManager& manager = DualConnectivityManager::instance();
 
@@ -36,18 +39,11 @@ Dual1DMeshBuilder::_buildDual1DMeshFrom(const IMesh& i_mesh)
   NodeValue<TinyVector<1>> dual_xr{dual_connectivity};
   primal_to_dual_1d_connectivity_data_mapper->toDualNode(primal_xr, primal_xj, dual_xr);
 
-  m_mesh = std::make_shared<MeshType>(p_dual_connectivity, dual_xr);
+  m_mesh = std::make_shared<MeshVariant>(std::make_shared<const Mesh<Connectivity<1>>>(p_dual_connectivity, dual_xr));
 }
 
-Dual1DMeshBuilder::Dual1DMeshBuilder(const IMesh& i_mesh)
+Dual1DMeshBuilder::Dual1DMeshBuilder(const std::shared_ptr<const MeshVariant>& mesh_v)
 {
   std::cout << "building Dual1DMesh\n";
-
-  if (i_mesh.dimension() == 1) {
-    this->_buildDual1DMeshFrom(i_mesh);
-  } else {
-    // LCOV_EXCL_START
-    throw UnexpectedError("invalid mesh dimension: " + stringify(i_mesh.dimension()));
-    // LCOV_EXCL_STOP
-  }
+  this->_buildDual1DMeshFrom(*(mesh_v->get<Mesh<Connectivity<1>>>()));
 }
diff --git a/src/mesh/Dual1DMeshBuilder.hpp b/src/mesh/Dual1DMeshBuilder.hpp
index d2b271aee..901a46fa5 100644
--- a/src/mesh/Dual1DMeshBuilder.hpp
+++ b/src/mesh/Dual1DMeshBuilder.hpp
@@ -3,15 +3,15 @@
 
 #include <mesh/MeshBuilderBase.hpp>
 
-#include <memory>
-
+class MeshVariant;
 class Dual1DMeshBuilder : public MeshBuilderBase
 {
  private:
-  void _buildDual1DMeshFrom(const IMesh&);
+  template <typename MeshType>
+  void _buildDual1DMeshFrom(const MeshType&);
 
   friend class DualMeshManager;
-  Dual1DMeshBuilder(const IMesh&);
+  Dual1DMeshBuilder(const std::shared_ptr<const MeshVariant>&);
 
  public:
   ~Dual1DMeshBuilder() = default;
diff --git a/src/mesh/DualMeshManager.cpp b/src/mesh/DualMeshManager.cpp
index 86384b6ad..99e4c7aa8 100644
--- a/src/mesh/DualMeshManager.cpp
+++ b/src/mesh/DualMeshManager.cpp
@@ -5,6 +5,7 @@
 #include <mesh/Dual1DMeshBuilder.hpp>
 #include <mesh/MedianDualMeshBuilder.hpp>
 #include <mesh/Mesh.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <utils/Exceptions.hpp>
 #include <utils/PugsAssert.hpp>
 
@@ -40,14 +41,14 @@ DualMeshManager::destroy()
 }
 
 void
-DualMeshManager::deleteMesh(const IMesh* p_mesh)
+DualMeshManager::deleteMesh(const size_t mesh_id)
 {
   bool has_removed = false;
   do {
     has_removed = false;
     for (const auto& [key, dual_mesh] : m_mesh_to_dual_mesh_map) {
-      const auto& [type, p_parent_mesh] = key;
-      if (p_mesh == p_parent_mesh) {
+      const auto& [type, p_parent_mesh_id] = key;
+      if (mesh_id == p_parent_mesh_id) {
         m_mesh_to_dual_mesh_map.erase(key);
         has_removed = true;
         break;
@@ -56,75 +57,63 @@ DualMeshManager::deleteMesh(const IMesh* p_mesh)
   } while (has_removed);
 }
 
-std::shared_ptr<const Mesh<Connectivity<1>>>
-DualMeshManager::getDual1DMesh(const Mesh<Connectivity<1>>& mesh)
+std::shared_ptr<const MeshVariant>
+DualMeshManager::getDual1DMesh(const std::shared_ptr<const MeshVariant>& mesh_v)
 {
-  const IMesh* p_mesh = &mesh;
-
-  auto key = std::make_pair(DualMeshType::Dual1D, p_mesh);
-  if (auto i_mesh_data = m_mesh_to_dual_mesh_map.find(key); i_mesh_data != m_mesh_to_dual_mesh_map.end()) {
-    return std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(i_mesh_data->second);
+  auto key = std::make_pair(DualMeshType::Dual1D, mesh_v->id());
+  if (auto i_mesh_to_dual_mesh = m_mesh_to_dual_mesh_map.find(key);
+      i_mesh_to_dual_mesh != m_mesh_to_dual_mesh_map.end()) {
+    return i_mesh_to_dual_mesh->second;
   } else {
-    Dual1DMeshBuilder builder{mesh};
-
+    Dual1DMeshBuilder builder{mesh_v};
     m_mesh_to_dual_mesh_map[key] = builder.mesh();
-    return std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(builder.mesh());
+    return builder.mesh();
+    ;
   }
 }
 
-template <>
-std::shared_ptr<const Mesh<Connectivity<1>>>
-DualMeshManager::getMedianDualMesh(const Mesh<Connectivity<1>>& mesh)
-{
-  return this->getDual1DMesh(mesh);
-}
-
-template <size_t Dimension>
-std::shared_ptr<const Mesh<Connectivity<Dimension>>>
-DualMeshManager::getMedianDualMesh(const Mesh<Connectivity<Dimension>>& mesh)
+std::shared_ptr<const MeshVariant>
+DualMeshManager::getMedianDualMesh(const std::shared_ptr<const MeshVariant>& mesh_v)
 {
-  static_assert(Dimension > 1);
-  const IMesh* p_mesh = &mesh;
-
-  auto key = std::make_pair(DualMeshType::Median, p_mesh);
-  if (auto i_mesh_data = m_mesh_to_dual_mesh_map.find(key); i_mesh_data != m_mesh_to_dual_mesh_map.end()) {
-    return std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh_data->second);
-  } else {
-    MedianDualMeshBuilder builder{mesh};
-
-    m_mesh_to_dual_mesh_map[key] = builder.mesh();
-    return std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(builder.mesh());
-  }
-}
-
-template std::shared_ptr<const Mesh<Connectivity<2>>> DualMeshManager::getMedianDualMesh(const Mesh<Connectivity<2>>&);
-template std::shared_ptr<const Mesh<Connectivity<3>>> DualMeshManager::getMedianDualMesh(const Mesh<Connectivity<3>>&);
-
-template <>
-std::shared_ptr<const Mesh<Connectivity<1>>>
-DualMeshManager::getDiamondDualMesh(const Mesh<Connectivity<1>>& mesh)
-{
-  return this->getDual1DMesh(mesh);
+  return std::visit(
+    [&](auto&& p_mesh) {
+      using MeshType = typename std::decay_t<decltype(p_mesh)>::element_type;
+      if constexpr (MeshType::Dimension == 1) {
+        return this->getDual1DMesh(mesh_v);
+      } else {
+        auto key = std::make_pair(DualMeshType::Median, mesh_v->id());
+        if (auto i_mesh_data = m_mesh_to_dual_mesh_map.find(key); i_mesh_data != m_mesh_to_dual_mesh_map.end()) {
+          return i_mesh_data->second;
+        } else {
+          MedianDualMeshBuilder builder{mesh_v};
+
+          m_mesh_to_dual_mesh_map[key] = builder.mesh();
+          return builder.mesh();
+        }
+      }
+    },
+    mesh_v->meshPointer());
 }
 
-template <size_t Dimension>
-std::shared_ptr<const Mesh<Connectivity<Dimension>>>
-DualMeshManager::getDiamondDualMesh(const Mesh<Connectivity<Dimension>>& mesh)
+std::shared_ptr<const MeshVariant>
+DualMeshManager::getDiamondDualMesh(const std::shared_ptr<const MeshVariant>& mesh_v)
 {
-  static_assert(Dimension > 1);
-
-  const IMesh* p_mesh = &mesh;
-
-  auto key = std::make_pair(DualMeshType::Diamond, p_mesh);
-  if (auto i_mesh_data = m_mesh_to_dual_mesh_map.find(key); i_mesh_data != m_mesh_to_dual_mesh_map.end()) {
-    return std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh_data->second);
-  } else {
-    DiamondDualMeshBuilder builder{mesh};
-
-    m_mesh_to_dual_mesh_map[key] = builder.mesh();
-    return std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(builder.mesh());
-  }
+  return std::visit(
+    [&](auto&& p_mesh) {
+      using MeshType = typename std::decay_t<decltype(p_mesh)>::element_type;
+      if constexpr (MeshType::Dimension == 1) {
+        return this->getDual1DMesh(mesh_v);
+      } else {
+        auto key = std::make_pair(DualMeshType::Diamond, mesh_v->id());
+        if (auto i_mesh_data = m_mesh_to_dual_mesh_map.find(key); i_mesh_data != m_mesh_to_dual_mesh_map.end()) {
+          return i_mesh_data->second;
+        } else {
+          DiamondDualMeshBuilder builder{mesh_v};
+
+          m_mesh_to_dual_mesh_map[key] = builder.mesh();
+          return builder.mesh();
+        }
+      }
+    },
+    mesh_v->meshPointer());
 }
-
-template std::shared_ptr<const Mesh<Connectivity<2>>> DualMeshManager::getDiamondDualMesh(const Mesh<Connectivity<2>>&);
-template std::shared_ptr<const Mesh<Connectivity<3>>> DualMeshManager::getDiamondDualMesh(const Mesh<Connectivity<3>>&);
diff --git a/src/mesh/DualMeshManager.hpp b/src/mesh/DualMeshManager.hpp
index 7b6358b70..040dfd8d6 100644
--- a/src/mesh/DualMeshManager.hpp
+++ b/src/mesh/DualMeshManager.hpp
@@ -2,13 +2,14 @@
 #define DUAL_MESH_MANAGER_HPP
 
 #include <mesh/DualMeshType.hpp>
-#include <mesh/IMesh.hpp>
 #include <utils/PugsAssert.hpp>
 #include <utils/PugsMacros.hpp>
 
 #include <memory>
 #include <unordered_map>
 
+class MeshVariant;
+
 template <size_t Dimension>
 class Connectivity;
 
@@ -18,7 +19,7 @@ class Mesh;
 class DualMeshManager
 {
  private:
-  using Key = std::pair<DualMeshType, const IMesh*>;
+  using Key = std::pair<DualMeshType, size_t>;
   struct HashKey
   {
     size_t
@@ -28,7 +29,7 @@ class DualMeshManager
     }
   };
 
-  std::unordered_map<Key, std::shared_ptr<const IMesh>, HashKey> m_mesh_to_dual_mesh_map;
+  std::unordered_map<Key, std::shared_ptr<const MeshVariant>, HashKey> m_mesh_to_dual_mesh_map;
 
   static DualMeshManager* m_instance;
 
@@ -50,15 +51,13 @@ class DualMeshManager
     return *m_instance;
   }
 
-  void deleteMesh(const IMesh*);
+  void deleteMesh(const size_t mesh_id);
 
-  std::shared_ptr<const Mesh<Connectivity<1>>> getDual1DMesh(const Mesh<Connectivity<1>>&);
+  std::shared_ptr<const MeshVariant> getDual1DMesh(const std::shared_ptr<const MeshVariant>&);
 
-  template <size_t Dimension>
-  std::shared_ptr<const Mesh<Connectivity<Dimension>>> getDiamondDualMesh(const Mesh<Connectivity<Dimension>>&);
+  std::shared_ptr<const MeshVariant> getDiamondDualMesh(const std::shared_ptr<const MeshVariant>&);
 
-  template <size_t Dimension>
-  std::shared_ptr<const Mesh<Connectivity<Dimension>>> getMedianDualMesh(const Mesh<Connectivity<Dimension>>&);
+  std::shared_ptr<const MeshVariant> getMedianDualMesh(const std::shared_ptr<const MeshVariant>&);
 };
 
 #endif   // DUAL_MESH_MANAGER_HPP
diff --git a/src/mesh/GmshReader.cpp b/src/mesh/GmshReader.cpp
index e05dcaae5..b8ddd2910 100644
--- a/src/mesh/GmshReader.cpp
+++ b/src/mesh/GmshReader.cpp
@@ -8,6 +8,7 @@
 #include <mesh/ConnectivityDispatcher.hpp>
 #include <mesh/ItemValueUtils.hpp>
 #include <mesh/Mesh.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <mesh/RefItemList.hpp>
 #include <utils/Exceptions.hpp>
 #include <utils/Stringify.hpp>
@@ -1065,7 +1066,7 @@ GmshReader::GmshReader(const std::string& filename) : m_filename(filename)
     const int mesh_dimension = [&]() {
       int mutable_mesh_dimension = -1;   // unknown mesh dimension
       if (m_mesh) {
-        mutable_mesh_dimension = m_mesh->dimension();
+        mutable_mesh_dimension = std::visit([](auto&& mesh) { return mesh->dimension(); }, m_mesh->meshPointer());
       }
 
       Array<int> dimensions = parallel::allGather(mutable_mesh_dimension);
@@ -1510,7 +1511,7 @@ GmshReader::__proceedData()
       xr[i][1] = m_mesh_data.__vertices[i][1];
       xr[i][2] = m_mesh_data.__vertices[i][2];
     }
-    m_mesh = std::make_shared<MeshType>(p_connectivity, xr);
+    m_mesh = std::make_shared<MeshVariant>(std::make_shared<const MeshType>(p_connectivity, xr));
     this->_checkMesh<3>();
 
   } else if (dot(dimension2_mask, elementNumber) > 0) {
@@ -1530,7 +1531,7 @@ GmshReader::__proceedData()
       xr[i][0] = m_mesh_data.__vertices[i][0];
       xr[i][1] = m_mesh_data.__vertices[i][1];
     }
-    m_mesh = std::make_shared<MeshType>(p_connectivity, xr);
+    m_mesh = std::make_shared<MeshVariant>(std::make_shared<const MeshType>(p_connectivity, xr));
     this->_checkMesh<2>();
 
   } else if (dot(dimension1_mask, elementNumber) > 0) {
@@ -1550,7 +1551,7 @@ GmshReader::__proceedData()
       xr[i][0] = m_mesh_data.__vertices[i][0];
     }
 
-    m_mesh = std::make_shared<MeshType>(p_connectivity, xr);
+    m_mesh = std::make_shared<MeshVariant>(std::make_shared<const MeshType>(p_connectivity, xr));
     this->_checkMesh<1>();
 
   } else {
diff --git a/src/mesh/GmshReader.hpp b/src/mesh/GmshReader.hpp
index 860695ef5..12be8c593 100644
--- a/src/mesh/GmshReader.hpp
+++ b/src/mesh/GmshReader.hpp
@@ -2,7 +2,6 @@
 #define GMSH_READER_HPP
 
 #include <algebra/TinyVector.hpp>
-#include <mesh/IMesh.hpp>
 #include <mesh/MeshBuilderBase.hpp>
 #include <mesh/RefId.hpp>
 #include <utils/Array.hpp>
diff --git a/src/mesh/IMesh.cpp b/src/mesh/IMesh.cpp
deleted file mode 100644
index e2a1739a8..000000000
--- a/src/mesh/IMesh.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <mesh/IMesh.hpp>
-
-#include <mesh/DualMeshManager.hpp>
-#include <mesh/MeshDataManager.hpp>
-
-IMesh::~IMesh()
-{
-  MeshDataManager::instance().deleteMeshData(this);
-  DualMeshManager::instance().deleteMesh(this);
-}
diff --git a/src/mesh/IMesh.hpp b/src/mesh/IMesh.hpp
deleted file mode 100644
index 350f0f2e6..000000000
--- a/src/mesh/IMesh.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef I_MESH_HPP
-#define I_MESH_HPP
-
-#include <cstddef>
-#include <iostream>
-
-class IMesh
-{
- protected:
-  virtual std::ostream& _write(std::ostream&) const = 0;
-
- public:
-  virtual size_t dimension() const = 0;
-
-  friend std::ostream&
-  operator<<(std::ostream& os, const IMesh& mesh)
-  {
-    return mesh._write(os);
-  }
-
-  IMesh(const IMesh&) = delete;
-  IMesh(IMesh&&)      = delete;
-
-  IMesh() = default;
-  virtual ~IMesh();
-};
-
-#endif   // I_MESH_HPP
diff --git a/src/mesh/MedianDualMeshBuilder.cpp b/src/mesh/MedianDualMeshBuilder.cpp
index 79d71dadc..095c44225 100644
--- a/src/mesh/MedianDualMeshBuilder.cpp
+++ b/src/mesh/MedianDualMeshBuilder.cpp
@@ -6,19 +6,19 @@
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshData.hpp>
 #include <mesh/MeshDataManager.hpp>
+#include <mesh/MeshTraits.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <mesh/PrimalToMedianDualConnectivityDataMapper.hpp>
 #include <utils/Stringify.hpp>
 
-template <size_t Dimension>
+template <typename MeshType>
 void
-MedianDualMeshBuilder::_buildMedianDualMeshFrom(const IMesh& i_mesh)
+MedianDualMeshBuilder::_buildMedianDualMeshFrom(const MeshType& primal_mesh)
 {
+  constexpr size_t Dimension = MeshType::Dimension;
   static_assert(Dimension > 1);
 
   using ConnectivityType = Connectivity<Dimension>;
-  using MeshType         = Mesh<Connectivity<Dimension>>;
-
-  const MeshType& primal_mesh = dynamic_cast<const MeshType&>(i_mesh);
 
   DualConnectivityManager& manager = DualConnectivityManager::instance();
 
@@ -39,24 +39,23 @@ MedianDualMeshBuilder::_buildMedianDualMeshFrom(const IMesh& i_mesh)
   NodeValue<TinyVector<Dimension>> dual_xr{dual_connectivity};
   primal_to_dual_connectivity_data_mapper->toDualNode(primal_xr, primal_xl, primal_xj, dual_xr);
 
-  m_mesh = std::make_shared<MeshType>(p_dual_connectivity, dual_xr);
+  m_mesh = std::make_shared<MeshVariant>(std::make_shared<const MeshType>(p_dual_connectivity, dual_xr));
 }
 
-MedianDualMeshBuilder::MedianDualMeshBuilder(const IMesh& i_mesh)
+MedianDualMeshBuilder::MedianDualMeshBuilder(const std::shared_ptr<const MeshVariant>& mesh_v)
 {
-  switch (i_mesh.dimension()) {
-  case 2: {
-    this->_buildMedianDualMeshFrom<2>(i_mesh);
-    break;
-  }
-  case 3: {
-    throw NotImplementedError("median dual mesh");
-    break;
-  }
-    // LCOV_EXCL_START
-  default: {
-    throw UnexpectedError("invalid mesh dimension: " + stringify(i_mesh.dimension()));
-  }
-    // LCOV_EXCL_STOP
-  }
+  std::visit(
+    [&](auto&& p_mesh) {
+      using MeshType = std::decay_t<decltype(p_mesh)>::element_type;
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        if constexpr (MeshType::Dimension > 1) {
+          this->_buildMedianDualMeshFrom(*p_mesh);
+        } else {
+          throw UnexpectedError("invalid polygonal mesh dimension");
+        }
+      } else {
+        throw UnexpectedError("invalid mesh type");
+      }
+    },
+    mesh_v->meshPointer());
 }
diff --git a/src/mesh/MedianDualMeshBuilder.hpp b/src/mesh/MedianDualMeshBuilder.hpp
index 6f8f1842c..ad31b6aa1 100644
--- a/src/mesh/MedianDualMeshBuilder.hpp
+++ b/src/mesh/MedianDualMeshBuilder.hpp
@@ -3,16 +3,15 @@
 
 #include <mesh/MeshBuilderBase.hpp>
 
-#include <memory>
-
+class MeshVariant;
 class MedianDualMeshBuilder : public MeshBuilderBase
 {
  private:
-  template <size_t Dimension>
-  void _buildMedianDualMeshFrom(const IMesh&);
+  template <typename MeshType>
+  void _buildMedianDualMeshFrom(const MeshType&);
 
   friend class DualMeshManager;
-  MedianDualMeshBuilder(const IMesh&);
+  MedianDualMeshBuilder(const std::shared_ptr<const MeshVariant>&);
 
  public:
   ~MedianDualMeshBuilder() = default;
diff --git a/src/mesh/Mesh.cpp b/src/mesh/Mesh.cpp
new file mode 100644
index 000000000..b622bfb97
--- /dev/null
+++ b/src/mesh/Mesh.cpp
@@ -0,0 +1,16 @@
+#include <mesh/Mesh.hpp>
+
+#include <mesh/Connectivity.hpp>
+#include <mesh/DualMeshManager.hpp>
+#include <mesh/MeshDataManager.hpp>
+
+template <typename ConnectivityType>
+Mesh<ConnectivityType>::~Mesh()
+{
+  MeshDataManager::instance().deleteMeshData(this->id());
+  DualMeshManager::instance().deleteMesh(this->id());
+}
+
+template Mesh<Connectivity<1>>::~Mesh();
+template Mesh<Connectivity<2>>::~Mesh();
+template Mesh<Connectivity<3>>::~Mesh();
diff --git a/src/mesh/Mesh.hpp b/src/mesh/Mesh.hpp
index 52cdd8bbf..451d53a31 100644
--- a/src/mesh/Mesh.hpp
+++ b/src/mesh/Mesh.hpp
@@ -2,13 +2,14 @@
 #define MESH_HPP
 
 #include <algebra/TinyVector.hpp>
-#include <mesh/IMesh.hpp>
 #include <mesh/ItemValue.hpp>
+#include <mesh/MeshVariant.hpp>
+#include <utils/GlobalVariableManager.hpp>
 
 #include <memory>
 
 template <typename ConnectivityType>
-class Mesh final : public IMesh
+class Mesh : public std::enable_shared_from_this<Mesh<ConnectivityType>>
 {
  public:
   using Connectivity = ConnectivityType;
@@ -17,18 +18,46 @@ class Mesh final : public IMesh
   using Rd                          = TinyVector<Dimension>;
 
  private:
+  const size_t m_id;
+
   const std::shared_ptr<const Connectivity> m_connectivity;
   const NodeValue<const Rd> m_xr;
 
   std::ostream&
-  _write(std::ostream& os) const final
+  _write(std::ostream& os) const
   {
     return os << *m_connectivity;
   }
 
  public:
+  friend std::ostream&
+  operator<<(std::ostream& os, const Mesh& mesh)
+  {
+    return mesh._write(os);
+  }
+
   PUGS_INLINE
   size_t
+  id() const
+  {
+    return m_id;
+  }
+
+  PUGS_INLINE
+  std::shared_ptr<const Mesh<ConnectivityType>>
+  shared_ptr() const
+  {
+    return this->shared_from_this();
+  }
+
+  PUGS_INLINE
+  operator std::shared_ptr<MeshVariant>() const
+  {
+    return std::make_shared<MeshVariant>(this->shared_ptr());
+  }
+
+  PUGS_INLINE
+  constexpr size_t
   dimension() const
   {
     return Dimension;
@@ -90,19 +119,19 @@ class Mesh final : public IMesh
     return m_xr;
   }
 
+  Mesh() = delete;
+
   PUGS_INLINE
   Mesh(const std::shared_ptr<const Connectivity>& connectivity, const NodeValue<const Rd>& xr)
-    : m_connectivity{connectivity}, m_xr{xr}
+    : m_id{GlobalVariableManager::instance().getAndIncrementMeshId()}, m_connectivity{connectivity}, m_xr{xr}
   {
     ;
   }
 
-  Mesh() = delete;
+  Mesh(const Mesh&) = delete;
+  Mesh(Mesh&&)      = delete;
 
-  ~Mesh()
-  {
-    ;
-  }
+  ~Mesh();
 };
 
 #endif   // MESH_HPP
diff --git a/src/mesh/MeshBuilderBase.cpp b/src/mesh/MeshBuilderBase.cpp
index d2b27cd14..6787e4bdc 100644
--- a/src/mesh/MeshBuilderBase.cpp
+++ b/src/mesh/MeshBuilderBase.cpp
@@ -7,6 +7,7 @@
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshData.hpp>
 #include <mesh/MeshDataManager.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <utils/PugsAssert.hpp>
 #include <utils/PugsMacros.hpp>
 
@@ -28,16 +29,16 @@ MeshBuilderBase::_dispatch()
     ConnectivityDescriptor descriptor;
     std::shared_ptr connectivity = ConnectivityType::build(descriptor);
     NodeValue<Rd> xr;
-    m_mesh = std::make_shared<MeshType>(connectivity, xr);
+    m_mesh = std::make_shared<MeshVariant>(std::make_shared<const MeshType>(connectivity, xr));
   }
 
-  const MeshType& mesh = dynamic_cast<const MeshType&>(*m_mesh);
+  const MeshType& mesh = *(m_mesh->get<const MeshType>());
   ConnectivityDispatcher<Dimension> dispatcher(mesh.connectivity());
 
   std::shared_ptr dispatched_connectivity = dispatcher.dispatchedConnectivity();
   NodeValue<Rd> dispatched_xr             = dispatcher.dispatch(mesh.xr());
 
-  m_mesh = std::make_shared<MeshType>(dispatched_connectivity, dispatched_xr);
+  m_mesh = std::make_shared<MeshVariant>(std::make_shared<const MeshType>(dispatched_connectivity, dispatched_xr));
 }
 
 template void MeshBuilderBase::_dispatch<1>();
@@ -55,7 +56,7 @@ MeshBuilderBase::_checkMesh() const
     throw UnexpectedError("mesh is not built yet");
   }
 
-  const MeshType& mesh = dynamic_cast<const MeshType&>(*m_mesh);
+  const MeshType& mesh = *(m_mesh->get<const MeshType>());
 
   const ConnectivityType& connectivity = mesh.connectivity();
 
diff --git a/src/mesh/MeshBuilderBase.hpp b/src/mesh/MeshBuilderBase.hpp
index 63c55ec56..665f0a88c 100644
--- a/src/mesh/MeshBuilderBase.hpp
+++ b/src/mesh/MeshBuilderBase.hpp
@@ -1,14 +1,14 @@
 #ifndef MESH_BUILDER_BASE_HPP
 #define MESH_BUILDER_BASE_HPP
 
-#include <mesh/IMesh.hpp>
+class MeshVariant;
 
 #include <memory>
 
 class MeshBuilderBase
 {
  protected:
-  std::shared_ptr<const IMesh> m_mesh;
+  std::shared_ptr<const MeshVariant> m_mesh;
 
   template <size_t Dimension>
   void _dispatch();
@@ -17,7 +17,7 @@ class MeshBuilderBase
   void _checkMesh() const;
 
  public:
-  std::shared_ptr<const IMesh>
+  std::shared_ptr<const MeshVariant>
   mesh() const
   {
     return m_mesh;
diff --git a/src/mesh/MeshData.cpp b/src/mesh/MeshData.cpp
index 2fdddb387..30ef6a015 100644
--- a/src/mesh/MeshData.cpp
+++ b/src/mesh/MeshData.cpp
@@ -3,6 +3,7 @@
 #include <mesh/Connectivity.hpp>
 #include <mesh/ItemValueVariant.hpp>
 #include <mesh/Mesh.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <output/NamedItemValueVariant.hpp>
 #include <output/VTKWriter.hpp>
 #include <utils/Exceptions.hpp>
@@ -12,7 +13,8 @@ void
 MeshData<Dimension>::_storeBadMesh()
 {
   VTKWriter writer("bad_mesh");
-  writer.writeOnMesh(std::make_shared<MeshType>(m_mesh.shared_connectivity(), m_mesh.xr()),
+  writer.writeOnMesh(std::make_shared<MeshVariant>(
+                       std::make_shared<const MeshType>(m_mesh.shared_connectivity(), m_mesh.xr())),
                      {std::make_shared<NamedItemValueVariant>(std::make_shared<ItemValueVariant>(m_Vj), "volume")});
   std::ostringstream error_msg;
   error_msg << "mesh contains cells of non-positive volume (see " << rang::fgB::yellow << "bad_mesh.pvd"
diff --git a/src/mesh/MeshDataManager.cpp b/src/mesh/MeshDataManager.cpp
index 8ca184a60..def1d1b61 100644
--- a/src/mesh/MeshDataManager.cpp
+++ b/src/mesh/MeshDataManager.cpp
@@ -22,10 +22,10 @@ MeshDataManager::destroy()
 {
   Assert(m_instance != nullptr, "MeshDataManager was not created!");
 
-  if (m_instance->m_mesh_mesh_data_map.size() > 0) {
+  if (m_instance->m_mesh_id_mesh_data_map.size() > 0) {
     std::stringstream error;
     error << ": some mesh data is still registered\n";
-    for (const auto& i_mesh_data : m_instance->m_mesh_mesh_data_map) {
+    for (const auto& i_mesh_data : m_instance->m_mesh_id_mesh_data_map) {
       error << " - mesh data " << rang::fgB::magenta << i_mesh_data.first << rang::style::reset << '\n';
     }
     throw UnexpectedError(error.str());
@@ -35,24 +35,22 @@ MeshDataManager::destroy()
 }
 
 void
-MeshDataManager::deleteMeshData(const IMesh* p_mesh)
+MeshDataManager::deleteMeshData(const size_t mesh_id)
 {
-  m_mesh_mesh_data_map.erase(p_mesh);
+  m_mesh_id_mesh_data_map.erase(mesh_id);
 }
 
 template <size_t Dimension>
 MeshData<Dimension>&
 MeshDataManager::getMeshData(const Mesh<Connectivity<Dimension>>& mesh)
 {
-  const IMesh* p_mesh = &mesh;
-
-  if (auto i_mesh_data = m_mesh_mesh_data_map.find(p_mesh); i_mesh_data != m_mesh_mesh_data_map.end()) {
+  if (auto i_mesh_data = m_mesh_id_mesh_data_map.find(mesh.id()); i_mesh_data != m_mesh_id_mesh_data_map.end()) {
     return dynamic_cast<MeshData<Dimension>&>(*i_mesh_data->second);
   } else {
     // **cannot** use make_shared since MeshData constructor is **private**
     std::shared_ptr<MeshData<Dimension>> mesh_data{new MeshData<Dimension>(mesh)};
 
-    m_mesh_mesh_data_map[p_mesh] = mesh_data;
+    m_mesh_id_mesh_data_map[mesh.id()] = mesh_data;
     return *mesh_data;
   }
 }
diff --git a/src/mesh/MeshDataManager.hpp b/src/mesh/MeshDataManager.hpp
index fd04101de..8b1672b52 100644
--- a/src/mesh/MeshDataManager.hpp
+++ b/src/mesh/MeshDataManager.hpp
@@ -8,8 +8,6 @@
 #include <memory>
 #include <unordered_map>
 
-class IMesh;
-
 template <size_t>
 class Connectivity;
 
@@ -22,7 +20,7 @@ class MeshData;
 class MeshDataManager
 {
  private:
-  std::unordered_map<const IMesh*, std::shared_ptr<IMeshData>> m_mesh_mesh_data_map;
+  std::unordered_map<size_t, std::shared_ptr<IMeshData>> m_mesh_id_mesh_data_map;
 
   static MeshDataManager* m_instance;
 
@@ -44,7 +42,7 @@ class MeshDataManager
     return *m_instance;
   }
 
-  void deleteMeshData(const IMesh*);
+  void deleteMeshData(const size_t mesh_id);
 
   template <size_t Dimension>
   MeshData<Dimension>& getMeshData(const Mesh<Connectivity<Dimension>>&);
diff --git a/src/mesh/MeshRandomizer.cpp b/src/mesh/MeshRandomizer.cpp
index 06028bab1..78c397c2e 100644
--- a/src/mesh/MeshRandomizer.cpp
+++ b/src/mesh/MeshRandomizer.cpp
@@ -9,13 +9,13 @@
 #include <mesh/MeshFlatNodeBoundary.hpp>
 #include <mesh/MeshLineNodeBoundary.hpp>
 #include <mesh/MeshNodeBoundary.hpp>
+#include <mesh/MeshTraits.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <scheme/AxisBoundaryConditionDescriptor.hpp>
 #include <scheme/FixedBoundaryConditionDescriptor.hpp>
 #include <scheme/SymmetryBoundaryConditionDescriptor.hpp>
 #include <utils/RandomEngine.hpp>
 
-#include <variant>
-
 template <size_t Dimension>
 class MeshRandomizerHandler::MeshRandomizer
 {
@@ -232,7 +232,7 @@ class MeshRandomizerHandler::MeshRandomizer
   }
 
  public:
-  std::shared_ptr<const IMesh>
+  std::shared_ptr<const MeshVariant>
   getRandomizedMesh() const
   {
     NodeValue<const Rd> given_xr = m_given_mesh.xr();
@@ -242,10 +242,10 @@ class MeshRandomizerHandler::MeshRandomizer
     parallel_for(
       m_given_mesh.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { xr[node_id] += given_xr[node_id]; });
 
-    return std::make_shared<MeshType>(m_given_mesh.shared_connectivity(), xr);
+    return std::make_shared<MeshVariant>(std::make_shared<const MeshType>(m_given_mesh.shared_connectivity(), xr));
   }
 
-  std::shared_ptr<const IMesh>
+  std::shared_ptr<const MeshVariant>
   getRandomizedMesh(const FunctionSymbolId& function_symbol_id) const
   {
     NodeValue<const Rd> given_xr = m_given_mesh.xr();
@@ -259,7 +259,7 @@ class MeshRandomizerHandler::MeshRandomizer
       m_given_mesh.numberOfNodes(),
       PUGS_LAMBDA(const NodeId node_id) { xr[node_id] = is_displaced[node_id] * xr[node_id] + given_xr[node_id]; });
 
-    return std::make_shared<MeshType>(m_given_mesh.shared_connectivity(), xr);
+    return std::make_shared<MeshVariant>(std::make_shared<const MeshType>(m_given_mesh.shared_connectivity(), xr));
   }
 
   MeshRandomizer(const MeshRandomizer&) = delete;
@@ -361,63 +361,39 @@ class MeshRandomizerHandler::MeshRandomizer<Dimension>::SymmetryBoundaryConditio
   ~SymmetryBoundaryCondition() = default;
 };
 
-std::shared_ptr<const IMesh>
+std::shared_ptr<const MeshVariant>
 MeshRandomizerHandler::getRandomizedMesh(
-  const IMesh& mesh,
+  const std::shared_ptr<const MeshVariant>& mesh_v,
   const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const
 {
-  switch (mesh.dimension()) {
-  case 1: {
-    constexpr size_t Dimension = 1;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshRandomizer randomizer(dynamic_cast<const MeshType&>(mesh), bc_descriptor_list);
-    return randomizer.getRandomizedMesh();
-  }
-  case 2: {
-    constexpr size_t Dimension = 2;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshRandomizer randomizer(dynamic_cast<const MeshType&>(mesh), bc_descriptor_list);
-    return randomizer.getRandomizedMesh();
-  }
-  case 3: {
-    constexpr size_t Dimension = 3;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshRandomizer randomizer(dynamic_cast<const MeshType&>(mesh), bc_descriptor_list);
-    return randomizer.getRandomizedMesh();
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      using MeshType = std::decay_t<decltype(mesh)>::element_type;
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        MeshRandomizer randomizer(*mesh, bc_descriptor_list);
+        return randomizer.getRandomizedMesh();
+      } else {
+        throw UnexpectedError("invalid mesh type");
+      }
+    },
+    mesh_v->meshPointer());
 }
 
-std::shared_ptr<const IMesh>
+std::shared_ptr<const MeshVariant>
 MeshRandomizerHandler::getRandomizedMesh(
-  const IMesh& mesh,
+  const std::shared_ptr<const MeshVariant>& mesh_v,
   const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
   const FunctionSymbolId& function_symbol_id) const
 {
-  switch (mesh.dimension()) {
-  case 1: {
-    constexpr size_t Dimension = 1;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshRandomizer randomizer(dynamic_cast<const MeshType&>(mesh), bc_descriptor_list);
-    return randomizer.getRandomizedMesh(function_symbol_id);
-  }
-  case 2: {
-    constexpr size_t Dimension = 2;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshRandomizer randomizer(dynamic_cast<const MeshType&>(mesh), bc_descriptor_list);
-    return randomizer.getRandomizedMesh(function_symbol_id);
-  }
-  case 3: {
-    constexpr size_t Dimension = 3;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshRandomizer randomizer(dynamic_cast<const MeshType&>(mesh), bc_descriptor_list);
-    return randomizer.getRandomizedMesh(function_symbol_id);
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      using MeshType = std::decay_t<decltype(mesh)>::element_type;
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        MeshRandomizer randomizer(*mesh, bc_descriptor_list);
+        return randomizer.getRandomizedMesh(function_symbol_id);
+      } else {
+        throw UnexpectedError("invalid mesh type");
+      }
+    },
+    mesh_v->meshPointer());
 }
diff --git a/src/mesh/MeshRandomizer.hpp b/src/mesh/MeshRandomizer.hpp
index f09aa7863..b71d99a67 100644
--- a/src/mesh/MeshRandomizer.hpp
+++ b/src/mesh/MeshRandomizer.hpp
@@ -1,12 +1,11 @@
 #ifndef MESH_RANDOMIZER_HPP
 #define MESH_RANDOMIZER_HPP
 
-#include <mesh/IMesh.hpp>
-#include <scheme/IBoundaryConditionDescriptor.hpp>
-
 #include <memory>
 #include <vector>
 
+class MeshVariant;
+class IBoundaryConditionDescriptor;
 class FunctionSymbolId;
 
 class MeshRandomizerHandler
@@ -16,12 +15,12 @@ class MeshRandomizerHandler
   class MeshRandomizer;
 
  public:
-  std::shared_ptr<const IMesh> getRandomizedMesh(
-    const IMesh& mesh,
+  std::shared_ptr<const MeshVariant> getRandomizedMesh(
+    const std::shared_ptr<const MeshVariant>& mesh_v,
     const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const;
 
-  std::shared_ptr<const IMesh> getRandomizedMesh(
-    const IMesh& mesh,
+  std::shared_ptr<const MeshVariant> getRandomizedMesh(
+    const std::shared_ptr<const MeshVariant>& mesh_v,
     const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
     const FunctionSymbolId& function_symbol_id) const;
 
diff --git a/src/mesh/MeshRelaxer.cpp b/src/mesh/MeshRelaxer.cpp
index bda3cc7d1..4ced5b385 100644
--- a/src/mesh/MeshRelaxer.cpp
+++ b/src/mesh/MeshRelaxer.cpp
@@ -2,18 +2,22 @@
 
 #include <mesh/Connectivity.hpp>
 #include <mesh/Mesh.hpp>
+#include <mesh/MeshTraits.hpp>
+#include <mesh/MeshVariant.hpp>
 
-template <typename ConnectivityType>
-std::shared_ptr<const Mesh<ConnectivityType>>
-MeshRelaxer::_relax(const Mesh<ConnectivityType>& source_mesh,
-                    const Mesh<ConnectivityType>& destination_mesh,
-                    const double& theta) const
+template <typename MeshType>
+std::shared_ptr<const MeshVariant>
+MeshRelaxer::_relax(const MeshType& source_mesh, const MeshType& destination_mesh, const double& theta) const
 {
+  static_assert(is_polygonal_mesh<MeshType>);
   if (source_mesh.shared_connectivity() == destination_mesh.shared_connectivity()) {
+    using ConnectivityType               = typename MeshType::Connectivity;
+    constexpr size_t Dimension           = MeshType::Dimension;
     const ConnectivityType& connectivity = source_mesh.connectivity();
-    NodeValue<TinyVector<ConnectivityType::Dimension>> theta_xr{connectivity};
-    const NodeValue<const TinyVector<ConnectivityType::Dimension>> source_xr      = source_mesh.xr();
-    const NodeValue<const TinyVector<ConnectivityType::Dimension>> destination_xr = destination_mesh.xr();
+
+    NodeValue<TinyVector<Dimension>> theta_xr{connectivity};
+    const NodeValue<const TinyVector<Dimension>> source_xr      = source_mesh.xr();
+    const NodeValue<const TinyVector<Dimension>> destination_xr = destination_mesh.xr();
 
     const double one_minus_theta = 1 - theta;
     parallel_for(
@@ -21,39 +25,26 @@ MeshRelaxer::_relax(const Mesh<ConnectivityType>& source_mesh,
         theta_xr[node_id] = one_minus_theta * source_xr[node_id] + theta * destination_xr[node_id];
       });
 
-    return std::make_shared<Mesh<ConnectivityType>>(source_mesh.shared_connectivity(), theta_xr);
+    return std::make_shared<MeshVariant>(std::make_shared<const MeshType>(source_mesh.shared_connectivity(), theta_xr));
   } else {
     throw NormalError("relaxed meshes must share the same connectivity");
   }
 }
 
-std::shared_ptr<const IMesh>
-MeshRelaxer::relax(const std::shared_ptr<const IMesh>& p_source_mesh,
-                   const std::shared_ptr<const IMesh>& p_destination_mesh,
+std::shared_ptr<const MeshVariant>
+MeshRelaxer::relax(const std::shared_ptr<const MeshVariant>& p_source_mesh,
+                   const std::shared_ptr<const MeshVariant>& p_destination_mesh,
                    const double& theta) const
 {
-  if (p_source_mesh->dimension() != p_destination_mesh->dimension()) {
-    throw NormalError("incompatible mesh dimensions");
-  } else {
-    switch (p_source_mesh->dimension()) {
-    case 1: {
-      using MeshType = Mesh<Connectivity<1>>;
-      return this->_relax(dynamic_cast<const MeshType&>(*p_source_mesh),
-                          dynamic_cast<const MeshType&>(*p_destination_mesh), theta);
-    }
-    case 2: {
-      using MeshType = Mesh<Connectivity<2>>;
-      return this->_relax(dynamic_cast<const MeshType&>(*p_source_mesh),
-                          dynamic_cast<const MeshType&>(*p_destination_mesh), theta);
-    }
-    case 3: {
-      using MeshType = Mesh<Connectivity<3>>;
-      return this->_relax(dynamic_cast<const MeshType&>(*p_source_mesh),
-                          dynamic_cast<const MeshType&>(*p_destination_mesh), theta);
-    }
-    default: {
-      throw UnexpectedError("invalid mesh dimension");
-    }
-    }
-  }
+  return std::visit(
+    [&](auto&& source_mesh, auto&& destination_mesh) -> std::shared_ptr<const MeshVariant> {
+      using SourceMeshType      = std::decay_t<decltype(source_mesh)>::element_type;
+      using DestinationMeshType = std::decay_t<decltype(destination_mesh)>::element_type;
+      if constexpr (std::is_same_v<SourceMeshType, DestinationMeshType>) {
+        return this->_relax(*source_mesh, *destination_mesh, theta);
+      } else {
+        throw UnexpectedError("invalid mesh dimension");
+      }
+    },
+    p_source_mesh->meshPointer(), p_destination_mesh->meshPointer());
 }
diff --git a/src/mesh/MeshRelaxer.hpp b/src/mesh/MeshRelaxer.hpp
index 96846cbad..deb9f8a4a 100644
--- a/src/mesh/MeshRelaxer.hpp
+++ b/src/mesh/MeshRelaxer.hpp
@@ -1,7 +1,7 @@
 #ifndef MESH_RELAXER_HPP
 #define MESH_RELAXER_HPP
 
-class IMesh;
+class MeshVariant;
 
 template <typename ConnectivityType>
 class Mesh;
@@ -11,15 +11,15 @@ class Mesh;
 class MeshRelaxer
 {
  private:
-  template <typename ConnectivityType>
-  std::shared_ptr<const Mesh<ConnectivityType>> _relax(const Mesh<ConnectivityType>& source_mesh,
-                                                       const Mesh<ConnectivityType>& destination_mesh,
-                                                       const double& theta) const;
+  template <typename MeshType>
+  std::shared_ptr<const MeshVariant> _relax(const MeshType& source_mesh,
+                                            const MeshType& destination_mesh,
+                                            const double& theta) const;
 
  public:
-  std::shared_ptr<const IMesh> relax(const std::shared_ptr<const IMesh>& p_source_mesh,
-                                     const std::shared_ptr<const IMesh>& p_destination_mesh,
-                                     const double& theta) const;
+  std::shared_ptr<const MeshVariant> relax(const std::shared_ptr<const MeshVariant>& p_source_mesh,
+                                           const std::shared_ptr<const MeshVariant>& p_destination_mesh,
+                                           const double& theta) const;
   MeshRelaxer()  = default;
   ~MeshRelaxer() = default;
 };
diff --git a/src/mesh/MeshSmoother.cpp b/src/mesh/MeshSmoother.cpp
index a9af80c01..281548bf1 100644
--- a/src/mesh/MeshSmoother.cpp
+++ b/src/mesh/MeshSmoother.cpp
@@ -10,6 +10,7 @@
 #include <mesh/MeshFlatNodeBoundary.hpp>
 #include <mesh/MeshLineNodeBoundary.hpp>
 #include <mesh/MeshNodeBoundary.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <scheme/AxisBoundaryConditionDescriptor.hpp>
 #include <scheme/DiscreteFunctionUtils.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
@@ -201,7 +202,7 @@ class MeshSmootherHandler::MeshSmoother
   }
 
  public:
-  std::shared_ptr<const IMesh>
+  std::shared_ptr<const MeshVariant>
   getSmoothedMesh() const
   {
     NodeValue<const Rd> given_xr = m_given_mesh.xr();
@@ -211,10 +212,10 @@ class MeshSmootherHandler::MeshSmoother
     parallel_for(
       m_given_mesh.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { xr[node_id] += given_xr[node_id]; });
 
-    return std::make_shared<MeshType>(m_given_mesh.shared_connectivity(), xr);
+    return std::make_shared<MeshVariant>(std::make_shared<const MeshType>(m_given_mesh.shared_connectivity(), xr));
   }
 
-  std::shared_ptr<const IMesh>
+  std::shared_ptr<const MeshVariant>
   getSmoothedMesh(const FunctionSymbolId& function_symbol_id) const
   {
     NodeValue<const Rd> given_xr = m_given_mesh.xr();
@@ -228,10 +229,10 @@ class MeshSmootherHandler::MeshSmoother
       m_given_mesh.numberOfNodes(),
       PUGS_LAMBDA(const NodeId node_id) { xr[node_id] = is_displaced[node_id] * xr[node_id] + given_xr[node_id]; });
 
-    return std::make_shared<MeshType>(m_given_mesh.shared_connectivity(), xr);
+    return std::make_shared<MeshVariant>(std::make_shared<const MeshType>(m_given_mesh.shared_connectivity(), xr));
   }
 
-  std::shared_ptr<const IMesh>
+  std::shared_ptr<const MeshVariant>
   getSmoothedMesh(const std::vector<std::shared_ptr<const IZoneDescriptor>>& zone_descriptor_list) const
   {
     NodeValue<const Rd> given_xr = m_given_mesh.xr();
@@ -268,10 +269,10 @@ class MeshSmootherHandler::MeshSmoother
       m_given_mesh.numberOfNodes(),
       PUGS_LAMBDA(const NodeId node_id) { xr[node_id] = is_displaced[node_id] * xr[node_id] + given_xr[node_id]; });
 
-    return std::make_shared<MeshType>(m_given_mesh.shared_connectivity(), xr);
+    return std::make_shared<MeshVariant>(std::make_shared<const MeshType>(m_given_mesh.shared_connectivity(), xr));
   }
 
-  std::shared_ptr<const IMesh>
+  std::shared_ptr<const MeshVariant>
   getSmoothedMesh(
     const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list) const
   {
@@ -305,7 +306,7 @@ class MeshSmootherHandler::MeshSmoother
       m_given_mesh.numberOfNodes(),
       PUGS_LAMBDA(const NodeId node_id) { xr[node_id] = is_displaced[node_id] * xr[node_id] + given_xr[node_id]; });
 
-    return std::make_shared<MeshType>(m_given_mesh.shared_connectivity(), xr);
+    return std::make_shared<MeshVariant>(std::make_shared<const MeshType>(m_given_mesh.shared_connectivity(), xr));
   }
 
   MeshSmoother(const MeshSmoother&) = delete;
@@ -407,135 +408,61 @@ class MeshSmootherHandler::MeshSmoother<Dimension>::SymmetryBoundaryCondition
   ~SymmetryBoundaryCondition() = default;
 };
 
-std::shared_ptr<const IMesh>
+std::shared_ptr<const MeshVariant>
 MeshSmootherHandler::getSmoothedMesh(
-  const std::shared_ptr<const IMesh>& mesh,
+  const std::shared_ptr<const MeshVariant>& mesh_v,
   const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const
 {
-  switch (mesh->dimension()) {
-  case 1: {
-    constexpr size_t Dimension = 1;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh();
-  }
-  case 2: {
-    constexpr size_t Dimension = 2;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh();
-  }
-  case 3: {
-    constexpr size_t Dimension = 3;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh();
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      MeshSmoother smoother(*mesh, bc_descriptor_list);
+      return smoother.getSmoothedMesh();
+    },
+    mesh_v->meshPointer());
 }
 
-std::shared_ptr<const IMesh>
+std::shared_ptr<const MeshVariant>
 MeshSmootherHandler::getSmoothedMesh(
-  const std::shared_ptr<const IMesh>& mesh,
+  const std::shared_ptr<const MeshVariant>& mesh_v,
   const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
   const FunctionSymbolId& function_symbol_id) const
 {
-  switch (mesh->dimension()) {
-  case 1: {
-    constexpr size_t Dimension = 1;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh(function_symbol_id);
-  }
-  case 2: {
-    constexpr size_t Dimension = 2;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh(function_symbol_id);
-  }
-  case 3: {
-    constexpr size_t Dimension = 3;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh(function_symbol_id);
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      MeshSmoother smoother(*mesh, bc_descriptor_list);
+      return smoother.getSmoothedMesh(function_symbol_id);
+    },
+    mesh_v->meshPointer());
 }
 
-std::shared_ptr<const IMesh>
+std::shared_ptr<const MeshVariant>
 MeshSmootherHandler::getSmoothedMesh(
-  const std::shared_ptr<const IMesh>& mesh,
+  const std::shared_ptr<const MeshVariant>& mesh_v,
   const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
   const std::vector<std::shared_ptr<const IZoneDescriptor>>& smoothing_zone_list) const
 {
-  switch (mesh->dimension()) {
-  case 1: {
-    constexpr size_t Dimension = 1;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh(smoothing_zone_list);
-  }
-  case 2: {
-    constexpr size_t Dimension = 2;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh(smoothing_zone_list);
-  }
-  case 3: {
-    constexpr size_t Dimension = 3;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh(smoothing_zone_list);
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      MeshSmoother smoother(*mesh, bc_descriptor_list);
+      return smoother.getSmoothedMesh(smoothing_zone_list);
+    },
+    mesh_v->meshPointer());
 }
 
-std::shared_ptr<const IMesh>
+std::shared_ptr<const MeshVariant>
 MeshSmootherHandler::getSmoothedMesh(
-  const std::shared_ptr<const IMesh>& mesh,
+  const std::shared_ptr<const MeshVariant>& mesh_v,
   const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
   const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list) const
 {
-  if (not hasSameMesh(discrete_function_variant_list)) {
-    throw NormalError("discrete functions are not defined on the same mesh");
-  }
-
-  std::shared_ptr<const IMesh> common_mesh = getCommonMesh(discrete_function_variant_list);
-
-  if (common_mesh != mesh) {
-    throw NormalError("discrete functions are not defined on the smoothed mesh");
+  if (not hasSameMesh(discrete_function_variant_list, mesh_v)) {
+    throw NormalError("discrete functions are not defined on the smooth mesh");
   }
 
-  switch (mesh->dimension()) {
-  case 1: {
-    constexpr size_t Dimension = 1;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh(discrete_function_variant_list);
-  }
-  case 2: {
-    constexpr size_t Dimension = 2;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh(discrete_function_variant_list);
-  }
-  case 3: {
-    constexpr size_t Dimension = 3;
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    MeshSmoother smoother(dynamic_cast<const MeshType&>(*mesh), bc_descriptor_list);
-    return smoother.getSmoothedMesh(discrete_function_variant_list);
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      MeshSmoother smoother(*mesh, bc_descriptor_list);
+      return smoother.getSmoothedMesh(discrete_function_variant_list);
+    },
+    mesh_v->meshPointer());
 }
diff --git a/src/mesh/MeshSmoother.hpp b/src/mesh/MeshSmoother.hpp
index 99db9bf76..209be6c13 100644
--- a/src/mesh/MeshSmoother.hpp
+++ b/src/mesh/MeshSmoother.hpp
@@ -1,13 +1,12 @@
 #ifndef MESH_SMOOTHER_HPP
 #define MESH_SMOOTHER_HPP
 
-#include <mesh/IMesh.hpp>
-#include <scheme/IBoundaryConditionDescriptor.hpp>
-
 #include <memory>
 #include <vector>
 
+class MeshVariant;
 class FunctionSymbolId;
+class IBoundaryConditionDescriptor;
 class IZoneDescriptor;
 class DiscreteFunctionVariant;
 
@@ -18,22 +17,22 @@ class MeshSmootherHandler
   class MeshSmoother;
 
  public:
-  std::shared_ptr<const IMesh> getSmoothedMesh(
-    const std::shared_ptr<const IMesh>& mesh,
+  std::shared_ptr<const MeshVariant> getSmoothedMesh(
+    const std::shared_ptr<const MeshVariant>& mesh_v,
     const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const;
 
-  std::shared_ptr<const IMesh> getSmoothedMesh(
-    const std::shared_ptr<const IMesh>& mesh,
+  std::shared_ptr<const MeshVariant> getSmoothedMesh(
+    const std::shared_ptr<const MeshVariant>& mesh_v,
     const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
     const FunctionSymbolId& function_symbol_id) const;
 
-  std::shared_ptr<const IMesh> getSmoothedMesh(
-    const std::shared_ptr<const IMesh>& mesh,
+  std::shared_ptr<const MeshVariant> getSmoothedMesh(
+    const std::shared_ptr<const MeshVariant>& mesh_v,
     const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
     const std::vector<std::shared_ptr<const IZoneDescriptor>>& smoothing_zone_list) const;
 
-  std::shared_ptr<const IMesh> getSmoothedMesh(
-    const std::shared_ptr<const IMesh>& mesh,
+  std::shared_ptr<const MeshVariant> getSmoothedMesh(
+    const std::shared_ptr<const MeshVariant>& mesh_v,
     const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
     const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& smoothing_zone_list) const;
 
diff --git a/src/mesh/MeshTraits.hpp b/src/mesh/MeshTraits.hpp
new file mode 100644
index 000000000..62ea22825
--- /dev/null
+++ b/src/mesh/MeshTraits.hpp
@@ -0,0 +1,21 @@
+#ifndef MESH_TRAITS_HPP
+#define MESH_TRAITS_HPP
+
+#include <cstddef>
+
+template <size_t>
+class Connectivity;
+
+template <typename ConnectivityType>
+class Mesh;
+
+template <typename MeshType>
+constexpr inline bool is_polygonal_mesh = false;
+
+template <size_t Dimension>
+constexpr inline bool is_polygonal_mesh<Mesh<Connectivity<Dimension>>> = true;
+
+template <size_t Dimension>
+constexpr inline bool is_polygonal_mesh<const Mesh<Connectivity<Dimension>>> = true;
+
+#endif   // MESH_TRAITS_HPP
diff --git a/src/mesh/MeshTransformer.cpp b/src/mesh/MeshTransformer.cpp
index 167c4f337..e524c0b2d 100644
--- a/src/mesh/MeshTransformer.cpp
+++ b/src/mesh/MeshTransformer.cpp
@@ -2,6 +2,7 @@
 
 #include <mesh/Connectivity.hpp>
 #include <mesh/Mesh.hpp>
+#include <mesh/MeshVariant.hpp>
 
 #include <language/utils/EvaluateAtPoints.hpp>
 
@@ -11,39 +12,29 @@ class MeshTransformer::MeshTransformation<OutputType(InputType)>
   static constexpr size_t Dimension = OutputType::Dimension;
 
  public:
-  static inline std::shared_ptr<Mesh<Connectivity<Dimension>>>
-  transform(const FunctionSymbolId& function_symbol_id, std::shared_ptr<const IMesh> p_mesh)
+  template <typename MeshType>
+  static std::shared_ptr<const MeshType>
+  transform(const FunctionSymbolId& function_symbol_id, const MeshType& mesh)
   {
-    using MeshType             = Mesh<Connectivity<Dimension>>;
-    const MeshType& given_mesh = dynamic_cast<const MeshType&>(*p_mesh);
-
-    NodeValue<OutputType> xr(given_mesh.connectivity());
-    NodeValue<const InputType> given_xr = given_mesh.xr();
+    NodeValue<OutputType> xr(mesh.connectivity());
+    NodeValue<const InputType> given_xr = mesh.xr();
     EvaluateAtPoints<OutputType(InputType)>::evaluateTo(function_symbol_id, given_xr, xr);
 
-    return std::make_shared<MeshType>(given_mesh.shared_connectivity(), xr);
+    return std::make_shared<const MeshType>(mesh.shared_connectivity(), xr);
   }
 };
 
-std::shared_ptr<const IMesh>
-MeshTransformer::transform(const FunctionSymbolId& function_id, std::shared_ptr<const IMesh> p_mesh)
+std::shared_ptr<const MeshVariant>
+MeshTransformer::transform(const FunctionSymbolId& function_id, std::shared_ptr<const MeshVariant> mesh_v)
 
 {
-  switch (p_mesh->dimension()) {
-  case 1: {
-    using TransformT = TinyVector<1>(TinyVector<1>);
-    return MeshTransformation<TransformT>::transform(function_id, p_mesh);
-  }
-  case 2: {
-    using TransformT = TinyVector<2>(TinyVector<2>);
-    return MeshTransformation<TransformT>::transform(function_id, p_mesh);
-  }
-  case 3: {
-    using TransformT = TinyVector<3>(TinyVector<3>);
-    return MeshTransformation<TransformT>::transform(function_id, p_mesh);
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      using MeshType             = std::decay_t<decltype(mesh)>::element_type;
+      constexpr size_t Dimension = MeshType::Dimension;
+      using TransformT           = TinyVector<Dimension>(TinyVector<Dimension>);
+
+      return std::make_shared<MeshVariant>(MeshTransformation<TransformT>::transform(function_id, *mesh));
+    },
+    mesh_v->meshPointer());
 }
diff --git a/src/mesh/MeshTransformer.hpp b/src/mesh/MeshTransformer.hpp
index ce0a4d47e..57687c395 100644
--- a/src/mesh/MeshTransformer.hpp
+++ b/src/mesh/MeshTransformer.hpp
@@ -1,11 +1,7 @@
 #ifndef MESH_TRANSFORMER_HPP
 #define MESH_TRANSFORMER_HPP
 
-class IMesh;
-
-template <typename ConnectivityType>
-class Mesh;
-
+class MeshVariant;
 class FunctionSymbolId;
 
 #include <memory>
@@ -16,8 +12,8 @@ class MeshTransformer
   class MeshTransformation;
 
  public:
-  std::shared_ptr<const IMesh> transform(const FunctionSymbolId& function_symbol_id,
-                                         std::shared_ptr<const IMesh> p_mesh);
+  std::shared_ptr<const MeshVariant> transform(const FunctionSymbolId& function_symbol_id,
+                                               std::shared_ptr<const MeshVariant> p_mesh);
 
   MeshTransformer()  = default;
   ~MeshTransformer() = default;
diff --git a/src/mesh/MeshUtils.cpp b/src/mesh/MeshUtils.cpp
new file mode 100644
index 000000000..3b8be38fa
--- /dev/null
+++ b/src/mesh/MeshUtils.cpp
@@ -0,0 +1,12 @@
+#include <mesh/MeshUtils.hpp>
+
+#include <mesh/Connectivity.hpp>
+#include <mesh/ConnectivityUtils.hpp>
+#include <mesh/Mesh.hpp>
+#include <mesh/MeshVariant.hpp>
+
+bool
+checkConnectivityOrdering(const std::shared_ptr<const MeshVariant>& mesh_v)
+{
+  return std::visit([](auto&& mesh) { return checkConnectivityOrdering(mesh->connectivity()); }, mesh_v->meshPointer());
+}
diff --git a/src/mesh/MeshUtils.hpp b/src/mesh/MeshUtils.hpp
new file mode 100644
index 000000000..27585f576
--- /dev/null
+++ b/src/mesh/MeshUtils.hpp
@@ -0,0 +1,10 @@
+#ifndef MESH_UTILS_HPP
+#define MESH_UTILS_HPP
+
+#include <memory>
+
+class MeshVariant;
+
+bool checkConnectivityOrdering(const std::shared_ptr<const MeshVariant>& mesh_v);
+
+#endif   // MESH_UTILS_HPP
diff --git a/src/mesh/MeshVariant.cpp b/src/mesh/MeshVariant.cpp
new file mode 100644
index 000000000..7b054297a
--- /dev/null
+++ b/src/mesh/MeshVariant.cpp
@@ -0,0 +1,17 @@
+#include <mesh/MeshVariant.hpp>
+
+#include <mesh/Connectivity.hpp>
+#include <mesh/Mesh.hpp>
+
+size_t
+MeshVariant::id() const
+{
+  return std::visit([](auto&& mesh) { return mesh->id(); }, m_p_mesh);
+}
+
+std::ostream&
+operator<<(std::ostream& os, const MeshVariant& mesh_v)
+{
+  std::visit([&](auto&& p_mesh) { os << *p_mesh; }, mesh_v.meshPointer());
+  return os;
+}
diff --git a/src/mesh/MeshVariant.hpp b/src/mesh/MeshVariant.hpp
new file mode 100644
index 000000000..bcc57e4cb
--- /dev/null
+++ b/src/mesh/MeshVariant.hpp
@@ -0,0 +1,56 @@
+#ifndef MESH_VARIANT_HPP
+#define MESH_VARIANT_HPP
+
+#include <utils/PugsMacros.hpp>
+
+#include <iostream>
+#include <memory>
+#include <variant>
+
+template <size_t>
+class Connectivity;
+
+template <typename ConnectivityType>
+class Mesh;
+
+class MeshVariant
+{
+ private:
+  using Variant = std::variant<std::shared_ptr<const Mesh<Connectivity<1>>>,
+                               std::shared_ptr<const Mesh<Connectivity<2>>>,
+                               std::shared_ptr<const Mesh<Connectivity<3>>>>;
+
+  Variant m_p_mesh;
+
+ public:
+  friend std::ostream& operator<<(std::ostream& os, const MeshVariant& mesh_v);
+
+  size_t id() const;
+
+  template <typename MeshType>
+  PUGS_INLINE std::shared_ptr<const MeshType>
+  get() const
+  {
+    return std::get<std::shared_ptr<const MeshType>>(m_p_mesh);
+  }
+
+  PUGS_INLINE
+  Variant
+  meshPointer() const
+  {
+    return m_p_mesh;
+  }
+
+  MeshVariant() = delete;
+
+  template <typename MeshType>
+  MeshVariant(const std::shared_ptr<const MeshType>& p_mesh) : m_p_mesh{p_mesh}
+  {}
+
+  MeshVariant(const MeshVariant&) = default;
+  MeshVariant(MeshVariant&&)      = default;
+
+  ~MeshVariant() = default;
+};
+
+#endif   // MESH_VARIANT_HPP
diff --git a/src/output/GnuplotWriter.cpp b/src/output/GnuplotWriter.cpp
index 8ccf77671..8d93fb117 100644
--- a/src/output/GnuplotWriter.cpp
+++ b/src/output/GnuplotWriter.cpp
@@ -5,6 +5,7 @@
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshData.hpp>
 #include <mesh/MeshDataManager.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <utils/Filesystem.hpp>
 #include <utils/Messenger.hpp>
 #include <utils/PugsTraits.hpp>
@@ -311,64 +312,55 @@ GnuplotWriter::_write(const MeshType& mesh,
 }
 
 void
-GnuplotWriter::_writeAtTime(const IMesh& mesh,
+GnuplotWriter::_writeAtTime(const MeshVariant& mesh_v,
                             const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                             double time) const
 {
   OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_data_list);
 
-  switch (mesh.dimension()) {
-  case 1: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<1>>&>(mesh), output_named_item_data_set, time);
-    break;
-  }
-  case 2: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<2>>&>(mesh), output_named_item_data_set, time);
-    break;
-  }
-  default: {
-    throw NormalError("gnuplot format is not available in dimension " + stringify(mesh.dimension()));
-  }
-  }
+  std::visit(
+    [&](auto&& p_mesh) {
+      using MeshType = typename std::decay_t<decltype(p_mesh)>::element_type;
+      if constexpr ((MeshType::Dimension == 1) or (MeshType::Dimension == 2)) {
+        this->_write(*p_mesh, output_named_item_data_set, time);
+      } else {
+        throw NormalError("gnuplot format is not available in dimension " + stringify(MeshType::Dimension));
+      }
+    },
+    mesh_v.meshPointer());
 }
 
 void
-GnuplotWriter::_writeMesh(const IMesh& mesh) const
+GnuplotWriter::_writeMesh(const MeshVariant& mesh_v) const
 {
   OutputNamedItemDataSet output_named_item_data_set{};
 
-  switch (mesh.dimension()) {
-  case 1: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<1>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  case 2: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<2>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  default: {
-    throw NormalError("gnuplot format is not available in dimension " + stringify(mesh.dimension()));
-  }
-  }
+  std::visit(
+    [&](auto&& p_mesh) {
+      using MeshType = typename std::decay_t<decltype(p_mesh)>::element_type;
+      if constexpr ((MeshType::Dimension == 1) or (MeshType::Dimension == 2)) {
+        this->_write(*p_mesh, output_named_item_data_set, {});
+      } else {
+        throw NormalError("gnuplot format is not available in dimension " + stringify(MeshType::Dimension));
+      }
+    },
+    mesh_v.meshPointer());
 }
 
 void
-GnuplotWriter::_write(const IMesh& mesh,
+GnuplotWriter::_write(const MeshVariant& mesh_v,
                       const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
 {
   OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_data_list);
 
-  switch (mesh.dimension()) {
-  case 1: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<1>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  case 2: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<2>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  default: {
-    throw NormalError("gnuplot format is not available in dimension " + stringify(mesh.dimension()));
-  }
-  }
+  std::visit(
+    [&](auto&& p_mesh) {
+      using MeshType = typename std::decay_t<decltype(p_mesh)>::element_type;
+      if constexpr ((MeshType::Dimension == 1) or (MeshType::Dimension == 2)) {
+        this->_write(*p_mesh, output_named_item_data_set, {});
+      } else {
+        throw NormalError("gnuplot format is not available in dimension " + stringify(MeshType::Dimension));
+      }
+    },
+    mesh_v.meshPointer());
 }
diff --git a/src/output/GnuplotWriter.hpp b/src/output/GnuplotWriter.hpp
index 6a4c6bd5b..9cf22a7ef 100644
--- a/src/output/GnuplotWriter.hpp
+++ b/src/output/GnuplotWriter.hpp
@@ -7,7 +7,7 @@
 #include <algebra/TinyVector.hpp>
 #include <output/OutputNamedItemValueSet.hpp>
 
-class IMesh;
+class MeshVariant;
 
 #include <optional>
 #include <string>
@@ -50,14 +50,14 @@ class GnuplotWriter final : public WriterBase
               const OutputNamedItemDataSet& output_named_item_data_set,
               std::optional<double> time) const;
 
-  void _writeAtTime(const IMesh& mesh,
+  void _writeAtTime(const MeshVariant& mesh_v,
                     const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                     double time) const final;
 
-  void _write(const IMesh& mesh,
+  void _write(const MeshVariant& mesh_v,
               const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const final;
 
-  void _writeMesh(const IMesh& mesh) const final;
+  void _writeMesh(const MeshVariant& mesh_v) const final;
 
  public:
   GnuplotWriter(const std::string& base_filename) : WriterBase(base_filename) {}
diff --git a/src/output/GnuplotWriter1D.cpp b/src/output/GnuplotWriter1D.cpp
index 6b8da7a7e..c839f9000 100644
--- a/src/output/GnuplotWriter1D.cpp
+++ b/src/output/GnuplotWriter1D.cpp
@@ -5,6 +5,7 @@
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshData.hpp>
 #include <mesh/MeshDataManager.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <utils/Filesystem.hpp>
 #include <utils/Messenger.hpp>
 #include <utils/PugsTraits.hpp>
@@ -348,7 +349,7 @@ GnuplotWriter1D::_write(const MeshType& mesh,
 }
 
 void
-GnuplotWriter1D::_writeMesh(const IMesh&) const
+GnuplotWriter1D::_writeMesh(const MeshVariant&) const
 {
   std::ostringstream errorMsg;
   errorMsg << "gnuplot_1d_writer does not write meshes\n"
@@ -358,47 +359,50 @@ GnuplotWriter1D::_writeMesh(const IMesh&) const
 }
 
 void
-GnuplotWriter1D::_writeAtTime(const IMesh& mesh,
+GnuplotWriter1D::_writeAtTime(const MeshVariant& mesh_v,
                               const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                               double time) const
 {
   OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_data_list);
 
-  switch (mesh.dimension()) {
-  case 1: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<1>>&>(mesh), output_named_item_data_set, time);
-    break;
-  }
-  case 2: {
-    std::ostringstream errorMsg;
-    errorMsg << "gnuplot_1d_writer is not available in dimension " << stringify(mesh.dimension()) << '\n'
-             << rang::style::bold << "note:" << rang::style::reset << " one can use " << rang::fgB::blue
-             << "gnuplot_writer" << rang::fg::reset << " in dimension 2";
-    throw NormalError(errorMsg.str());
-  }
-  default: {
-    throw NormalError("gnuplot format is not available in dimension " + stringify(mesh.dimension()));
-  }
-  }
+  std::visit(
+    [&](auto&& p_mesh) {
+      using MeshType = typename std::decay_t<decltype(p_mesh)>::element_type;
+      if constexpr (MeshType::Dimension == 1) {
+        this->_write(*p_mesh, output_named_item_data_set, time);
+      } else if constexpr (MeshType::Dimension == 2) {
+        std::ostringstream errorMsg;
+        errorMsg << "gnuplot_1d_writer is not available in dimension " << stringify(MeshType::Dimension) << '\n'
+                 << rang::style::bold << "note:" << rang::style::reset << " one can use " << rang::fgB::blue
+                 << "gnuplot_writer" << rang::fg::reset << " in dimension 2";
+        throw NormalError(errorMsg.str());
+      } else {
+        throw NormalError("gnuplot format is not available in dimension " + stringify(MeshType::Dimension));
+      }
+    },
+    mesh_v.meshPointer());
 }
 
 void
-GnuplotWriter1D::_write(const IMesh& mesh,
+GnuplotWriter1D::_write(const MeshVariant& mesh_v,
                         const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
 {
   OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_data_list);
 
-  switch (mesh.dimension()) {
-  case 1: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<1>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  case 2: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<2>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  default: {
-    throw NormalError("gnuplot format is not available in dimension " + stringify(mesh.dimension()));
-  }
-  }
+  std::visit(
+    [&](auto&& p_mesh) {
+      using MeshType = typename std::decay_t<decltype(p_mesh)>::element_type;
+      if constexpr (MeshType::Dimension == 1) {
+        this->_write(*p_mesh, output_named_item_data_set, {});
+      } else if constexpr (MeshType::Dimension == 2) {
+        std::ostringstream errorMsg;
+        errorMsg << "gnuplot_1d_writer is not available in dimension " << stringify(MeshType::Dimension) << '\n'
+                 << rang::style::bold << "note:" << rang::style::reset << " one can use " << rang::fgB::blue
+                 << "gnuplot_writer" << rang::fg::reset << " in dimension 2";
+        throw NormalError(errorMsg.str());
+      } else {
+        throw NormalError("gnuplot format is not available in dimension " + stringify(MeshType::Dimension));
+      }
+    },
+    mesh_v.meshPointer());
 }
diff --git a/src/output/GnuplotWriter1D.hpp b/src/output/GnuplotWriter1D.hpp
index fd0cac99b..61b697dd1 100644
--- a/src/output/GnuplotWriter1D.hpp
+++ b/src/output/GnuplotWriter1D.hpp
@@ -7,7 +7,7 @@
 #include <algebra/TinyVector.hpp>
 #include <output/OutputNamedItemValueSet.hpp>
 
-class IMesh;
+class MeshVariant;
 
 #include <optional>
 #include <string>
@@ -49,14 +49,14 @@ class GnuplotWriter1D final : public WriterBase
               const OutputNamedItemDataSet& output_named_item_value_set,
               std::optional<double> time) const;
 
-  void _writeAtTime(const IMesh& mesh,
+  void _writeAtTime(const MeshVariant& mesh_v,
                     const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                     double time) const final;
 
-  void _write(const IMesh& mesh,
+  void _write(const MeshVariant& mesh_v,
               const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const final;
 
-  void _writeMesh(const IMesh& mesh) const final;
+  void _writeMesh(const MeshVariant& mesh_v) const final;
 
  public:
   GnuplotWriter1D(const std::string& base_filename) : WriterBase(base_filename) {}
diff --git a/src/output/IWriter.hpp b/src/output/IWriter.hpp
index 14c773300..3d821fdac 100644
--- a/src/output/IWriter.hpp
+++ b/src/output/IWriter.hpp
@@ -6,13 +6,13 @@
 #include <memory>
 #include <vector>
 
-class IMesh;
+class MeshVariant;
 
 class IWriter
 {
  public:
-  virtual void writeMesh(const std::shared_ptr<const IMesh>& mesh) const = 0;
-  virtual void writeMesh(const IMesh& mesh) const                        = 0;
+  virtual void writeMesh(const std::shared_ptr<const MeshVariant>& mesh_v) const = 0;
+  virtual void writeMesh(const MeshVariant& mesh_v) const                        = 0;
 
   virtual void write(const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const = 0;
 
@@ -23,15 +23,15 @@ class IWriter
                            double time) const = 0;
 
   virtual void writeOnMesh(
-    const std::shared_ptr<const IMesh>& mesh,
+    const std::shared_ptr<const MeshVariant>& mesh_v,
     const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const = 0;
 
   virtual void writeOnMeshIfNeeded(
-    const std::shared_ptr<const IMesh>& mesh,
+    const std::shared_ptr<const MeshVariant>& mesh_v,
     const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
     double time) const = 0;
 
-  virtual void writeOnMeshForced(const std::shared_ptr<const IMesh>& mesh,
+  virtual void writeOnMeshForced(const std::shared_ptr<const MeshVariant>& mesh_v,
                                  const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                                  double time) const = 0;
 
diff --git a/src/output/VTKWriter.cpp b/src/output/VTKWriter.cpp
index 6ec6295e4..be606c829 100644
--- a/src/output/VTKWriter.cpp
+++ b/src/output/VTKWriter.cpp
@@ -4,6 +4,7 @@
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshData.hpp>
 #include <mesh/MeshDataManager.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <utils/Filesystem.hpp>
 #include <utils/Messenger.hpp>
 #include <utils/RevisionInfo.hpp>
@@ -682,76 +683,28 @@ VTKWriter::_write(const MeshType& mesh,
 }
 
 void
-VTKWriter::_writeMesh(const IMesh& mesh) const
+VTKWriter::_writeMesh(const MeshVariant& mesh_v) const
 {
   OutputNamedItemDataSet output_named_item_data_set;
 
-  switch (mesh.dimension()) {
-  case 1: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<1>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  case 2: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<2>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  case 3: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<3>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  std::visit([&](auto&& p_mesh) { this->_write(*p_mesh, output_named_item_data_set, {}); }, mesh_v.meshPointer());
 }
 
 void
-VTKWriter::_writeAtTime(const IMesh& mesh,
+VTKWriter::_writeAtTime(const MeshVariant& mesh_v,
                         const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                         double time) const
 {
   OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_data_list);
 
-  switch (mesh.dimension()) {
-  case 1: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<1>>&>(mesh), output_named_item_data_set, time);
-    break;
-  }
-  case 2: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<2>>&>(mesh), output_named_item_data_set, time);
-    break;
-  }
-  case 3: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<3>>&>(mesh), output_named_item_data_set, time);
-    break;
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  std::visit([&](auto&& p_mesh) { this->_write(*p_mesh, output_named_item_data_set, time); }, mesh_v.meshPointer());
 }
 
 void
-VTKWriter::_write(const IMesh& mesh,
+VTKWriter::_write(const MeshVariant& mesh_v,
                   const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
 {
   OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_data_list);
 
-  switch (mesh.dimension()) {
-  case 1: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<1>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  case 2: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<2>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  case 3: {
-    this->_write(dynamic_cast<const Mesh<Connectivity<3>>&>(mesh), output_named_item_data_set, {});
-    break;
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  std::visit([&](auto&& p_mesh) { this->_write(*p_mesh, output_named_item_data_set, {}); }, mesh_v.meshPointer());
 }
diff --git a/src/output/VTKWriter.hpp b/src/output/VTKWriter.hpp
index 1fa439e94..1141daec8 100644
--- a/src/output/VTKWriter.hpp
+++ b/src/output/VTKWriter.hpp
@@ -7,8 +7,6 @@
 #include <algebra/TinyVector.hpp>
 #include <output/OutputNamedItemValueSet.hpp>
 
-class IMesh;
-
 #include <optional>
 #include <string>
 
@@ -100,14 +98,14 @@ class VTKWriter final : public WriterBase
               const OutputNamedItemDataSet& output_named_item_data_set,
               std::optional<double> time) const;
 
-  void _writeAtTime(const IMesh& mesh,
+  void _writeAtTime(const MeshVariant& mesh_v,
                     const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                     double time) const final;
 
-  void _write(const IMesh& mesh,
+  void _write(const MeshVariant& mesh_v,
               const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const final;
 
-  void _writeMesh(const IMesh& mesh) const final;
+  void _writeMesh(const MeshVariant& mesh_v) const final;
 
  public:
   VTKWriter(const std::string& base_filename) : WriterBase(base_filename) {}
diff --git a/src/output/WriterBase.cpp b/src/output/WriterBase.cpp
index a96da1e4e..11d37def8 100644
--- a/src/output/WriterBase.cpp
+++ b/src/output/WriterBase.cpp
@@ -1,8 +1,9 @@
 #include <output/WriterBase.hpp>
 
-#include <mesh/IMesh.hpp>
 #include <mesh/ItemArrayVariant.hpp>
 #include <mesh/ItemValueVariant.hpp>
+#include <mesh/Mesh.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <output/NamedDiscreteFunction.hpp>
 #include <output/NamedItemArrayVariant.hpp>
 #include <output/NamedItemValueVariant.hpp>
@@ -29,27 +30,14 @@ WriterBase::_registerDiscreteFunction(const std::string& name,
 
 void
 WriterBase::_checkConnectivity(
-  const std::shared_ptr<const IMesh>& mesh,
+  const std::shared_ptr<const MeshVariant>& mesh_v,
   const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
 {
   Assert(named_discrete_data_list.size() > 0);
 
-  std::shared_ptr<const IConnectivity> connectivity = [&]() -> std::shared_ptr<const IConnectivity> {
-    switch (mesh->dimension()) {
-    case 1: {
-      return dynamic_cast<const Mesh<Connectivity<1>>&>(*mesh).shared_connectivity();
-    }
-    case 2: {
-      return dynamic_cast<const Mesh<Connectivity<2>>&>(*mesh).shared_connectivity();
-    }
-    case 3: {
-      return dynamic_cast<const Mesh<Connectivity<3>>&>(*mesh).shared_connectivity();
-    }
-    default: {
-      throw UnexpectedError("invalid dimension");
-    }
-    }
-  }();
+  std::shared_ptr<const IConnectivity> connectivity =
+    std::visit([&](auto&& p_mesh) -> std::shared_ptr<const IConnectivity> { return p_mesh->shared_connectivity(); },
+               mesh_v->meshPointer());
 
   for (size_t i = 0; i < named_discrete_data_list.size(); ++i) {
     const auto& named_discrete_data = named_discrete_data_list[i];
@@ -142,11 +130,13 @@ WriterBase::_checkSignature(
 }
 
 void
-WriterBase::_checkMesh(const std::shared_ptr<const IMesh>& mesh,
+WriterBase::_checkMesh(const std::shared_ptr<const MeshVariant>& mesh_v,
                        const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
 {
   Assert(named_discrete_data_list.size() > 0);
 
+  const size_t mesh_id = std::visit([](auto&& p_mesh) { return p_mesh->id(); }, mesh_v->meshPointer());
+
   for (size_t i = 0; i < named_discrete_data_list.size(); ++i) {
     const auto& named_discrete_data = named_discrete_data_list[i];
 
@@ -154,11 +144,11 @@ WriterBase::_checkMesh(const std::shared_ptr<const IMesh>& mesh,
       const NamedDiscreteFunction& named_discrete_function =
         dynamic_cast<const NamedDiscreteFunction&>(*named_discrete_data);
 
-      std::shared_ptr<const IMesh> discrete_function_mesh =
-        std::visit([](auto&& f) { return f.mesh(); },
+      const size_t discrete_function_mesh_id =
+        std::visit([](auto&& f) { return f.mesh()->id(); },
                    named_discrete_function.discreteFunctionVariant()->discreteFunction());
 
-      if (mesh != discrete_function_mesh) {
+      if (mesh_id != discrete_function_mesh_id) {
         std::ostringstream error_msg;
         error_msg << "The variable " << rang::fgB::yellow << named_discrete_function.name() << rang::fg::reset
                   << " is not defined on the provided mesh\n";
@@ -168,12 +158,14 @@ WriterBase::_checkMesh(const std::shared_ptr<const IMesh>& mesh,
   }
 }
 
-std::shared_ptr<const IMesh>
+std::shared_ptr<const MeshVariant>
 WriterBase::_getMesh(const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
 {
   Assert(named_discrete_data_list.size() > 0);
 
-  std::map<std::shared_ptr<const IMesh>, std::string> mesh_set;
+  std::shared_ptr<const MeshVariant> mesh_v;
+
+  std::map<size_t, std::string> mesh_id_to_function_name_map;
   std::map<std::shared_ptr<const IConnectivity>, std::string> connectivity_set;
 
   for (size_t i = 0; i < named_discrete_data_list.size(); ++i) {
@@ -184,30 +176,16 @@ WriterBase::_getMesh(const std::vector<std::shared_ptr<const INamedDiscreteData>
       const NamedDiscreteFunction& named_discrete_function =
         dynamic_cast<const NamedDiscreteFunction&>(*named_discrete_data);
 
-      std::shared_ptr mesh = std::visit([&](auto&& f) { return f.mesh(); },
-                                        named_discrete_function.discreteFunctionVariant()->discreteFunction());
-      mesh_set[mesh]       = named_discrete_function.name();
+      std::visit(
+        [&](auto&& f) {
+          mesh_id_to_function_name_map[f.mesh()->id()] = named_discrete_function.name();
+          if (not mesh_v) {
+            mesh_v = std::make_shared<MeshVariant>(f.mesh());
+          }
+          connectivity_set[f.mesh()->shared_connectivity()] = named_discrete_function.name();
+        },
+        named_discrete_function.discreteFunctionVariant()->discreteFunction());
 
-      switch (mesh->dimension()) {
-      case 1: {
-        connectivity_set[dynamic_cast<const Mesh<Connectivity<1>>&>(*mesh).shared_connectivity()] =
-          named_discrete_function.name();
-        break;
-      }
-      case 2: {
-        connectivity_set[dynamic_cast<const Mesh<Connectivity<2>>&>(*mesh).shared_connectivity()] =
-          named_discrete_function.name();
-        break;
-      }
-      case 3: {
-        connectivity_set[dynamic_cast<const Mesh<Connectivity<3>>&>(*mesh).shared_connectivity()] =
-          named_discrete_function.name();
-        break;
-      }
-      default: {
-        throw UnexpectedError("invalid dimension");
-      }
-      }
       break;
     }
     case INamedDiscreteData::Type::item_value: {
@@ -233,8 +211,8 @@ WriterBase::_getMesh(const std::vector<std::shared_ptr<const INamedDiscreteData>
     }
   }
 
-  if (mesh_set.size() != 1) {
-    if (mesh_set.size() == 0) {
+  if (mesh_id_to_function_name_map.size() != 1) {
+    if (mesh_id_to_function_name_map.size() == 0) {
       throw NormalError("cannot find any mesh associated to output quantities");
     } else {
       std::ostringstream error_msg;
@@ -242,7 +220,7 @@ WriterBase::_getMesh(const std::vector<std::shared_ptr<const INamedDiscreteData>
                 << " in the same file!\n";
       error_msg << rang::fgB::yellow << "note:" << rang::fg::reset
                 << "the following variables are defined on different meshes:";
-      for (const auto& [mesh, name] : mesh_set) {
+      for (const auto& [mesh, name] : mesh_id_to_function_name_map) {
         error_msg << "\n- " << name;
       }
       throw NormalError(error_msg.str());
@@ -261,7 +239,7 @@ WriterBase::_getMesh(const std::vector<std::shared_ptr<const INamedDiscreteData>
     throw NormalError(error_msg.str());
   }
 
-  return mesh_set.begin()->first;
+  return mesh_v;
 }
 
 OutputNamedItemDataSet
@@ -334,7 +312,7 @@ WriterBase::write(const std::vector<std::shared_ptr<const INamedDiscreteData>>&
   if (m_period_manager.has_value()) {
     throw NormalError("this writer requires time value");
   } else {
-    std::shared_ptr<const IMesh> mesh = _getMesh(named_discrete_data_list);
+    std::shared_ptr<const MeshVariant> mesh = _getMesh(named_discrete_data_list);
     this->_write(*mesh, named_discrete_data_list);
   }
 }
@@ -349,7 +327,7 @@ WriterBase::writeIfNeeded(const std::vector<std::shared_ptr<const INamedDiscrete
       return;   // output already performed
 
     if (time >= m_period_manager->nextTime()) {
-      std::shared_ptr<const IMesh> mesh = _getMesh(named_discrete_data_list);
+      std::shared_ptr<const MeshVariant> mesh = _getMesh(named_discrete_data_list);
       this->_checkSignature(named_discrete_data_list);
       this->_writeAtTime(*mesh, named_discrete_data_list, time);
       m_period_manager->setSaveTime(time);
@@ -367,7 +345,7 @@ WriterBase::writeForced(const std::vector<std::shared_ptr<const INamedDiscreteDa
     if (time == m_period_manager->getLastTime())
       return;   // output already performed
 
-    std::shared_ptr<const IMesh> mesh = _getMesh(named_discrete_data_list);
+    std::shared_ptr<const MeshVariant> mesh = _getMesh(named_discrete_data_list);
     this->_checkSignature(named_discrete_data_list);
     this->_writeAtTime(*mesh, named_discrete_data_list, time);
     m_period_manager->setSaveTime(time);
@@ -377,7 +355,7 @@ WriterBase::writeForced(const std::vector<std::shared_ptr<const INamedDiscreteDa
 }
 
 void
-WriterBase::writeOnMesh(const std::shared_ptr<const IMesh>& mesh,
+WriterBase::writeOnMesh(const std::shared_ptr<const MeshVariant>& mesh,
                         const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
 {
   if (m_period_manager.has_value()) {
@@ -390,7 +368,7 @@ WriterBase::writeOnMesh(const std::shared_ptr<const IMesh>& mesh,
 }
 
 void
-WriterBase::writeOnMeshIfNeeded(const std::shared_ptr<const IMesh>& mesh,
+WriterBase::writeOnMeshIfNeeded(const std::shared_ptr<const MeshVariant>& mesh,
                                 const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                                 double time) const
 {
@@ -409,7 +387,7 @@ WriterBase::writeOnMeshIfNeeded(const std::shared_ptr<const IMesh>& mesh,
 }
 
 void
-WriterBase::writeOnMeshForced(const std::shared_ptr<const IMesh>& mesh,
+WriterBase::writeOnMeshForced(const std::shared_ptr<const MeshVariant>& mesh,
                               const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                               double time) const
 {
@@ -427,13 +405,13 @@ WriterBase::writeOnMeshForced(const std::shared_ptr<const IMesh>& mesh,
 }
 
 void
-WriterBase::writeMesh(const std::shared_ptr<const IMesh>& mesh) const
+WriterBase::writeMesh(const std::shared_ptr<const MeshVariant>& mesh) const
 {
   writeMesh(*mesh);
 }
 
 void
-WriterBase::writeMesh(const IMesh& mesh) const
+WriterBase::writeMesh(const MeshVariant& mesh) const
 {
   if (m_period_manager.has_value()) {
     throw NormalError("write_mesh requires a writer without time period");
diff --git a/src/output/WriterBase.hpp b/src/output/WriterBase.hpp
index 707ac52d3..1964068a0 100644
--- a/src/output/WriterBase.hpp
+++ b/src/output/WriterBase.hpp
@@ -8,7 +8,7 @@
 #include <optional>
 #include <string>
 
-class IMesh;
+class MeshVariant;
 class OutputNamedItemDataSet;
 class NamedDiscreteFunction;
 
@@ -94,26 +94,26 @@ class WriterBase : public IWriter
   static void _registerDiscreteFunction(const std::string& name, const DiscreteFunctionType&, OutputNamedItemDataSet&);
 
  protected:
-  void _checkConnectivity(const std::shared_ptr<const IMesh>& mesh,
+  void _checkConnectivity(const std::shared_ptr<const MeshVariant>& mesh_v,
                           const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const;
 
-  void _checkMesh(const std::shared_ptr<const IMesh>& mesh,
+  void _checkMesh(const std::shared_ptr<const MeshVariant>& mesh_v,
                   const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const;
 
-  std::shared_ptr<const IMesh> _getMesh(
+  std::shared_ptr<const MeshVariant> _getMesh(
     const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const;
 
   OutputNamedItemDataSet _getOutputNamedItemDataSet(
     const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const;
 
-  virtual void _writeAtTime(const IMesh& mesh,
+  virtual void _writeAtTime(const MeshVariant& mesh_v,
                             const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                             double time) const = 0;
 
-  virtual void _write(const IMesh& mesh,
+  virtual void _write(const MeshVariant& mesh_v,
                       const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const = 0;
 
-  virtual void _writeMesh(const IMesh& mesh) const = 0;
+  virtual void _writeMesh(const MeshVariant& mesh_v) const = 0;
 
  public:
   void write(const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const final;
@@ -124,18 +124,18 @@ class WriterBase : public IWriter
   void writeForced(const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                    double time) const final;
 
-  void writeOnMesh(const std::shared_ptr<const IMesh>& mesh,
+  void writeOnMesh(const std::shared_ptr<const MeshVariant>& mesh_v,
                    const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const final;
 
-  void writeOnMeshIfNeeded(const std::shared_ptr<const IMesh>& mesh,
+  void writeOnMeshIfNeeded(const std::shared_ptr<const MeshVariant>& mesh_v,
                            const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                            double time) const final;
-  void writeOnMeshForced(const std::shared_ptr<const IMesh>& mesh,
+  void writeOnMeshForced(const std::shared_ptr<const MeshVariant>& mesh_v,
                          const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
                          double time) const final;
 
-  void writeMesh(const std::shared_ptr<const IMesh>& mesh) const final;
-  void writeMesh(const IMesh& mesh) const final;
+  void writeMesh(const std::shared_ptr<const MeshVariant>& mesh_v) const final;
+  void writeMesh(const MeshVariant& mesh_v) const final;
 
   WriterBase() = delete;
 
diff --git a/src/scheme/AcousticSolver.cpp b/src/scheme/AcousticSolver.cpp
index f61f27cb4..575a281c1 100644
--- a/src/scheme/AcousticSolver.cpp
+++ b/src/scheme/AcousticSolver.cpp
@@ -6,6 +6,8 @@
 #include <mesh/MeshFaceBoundary.hpp>
 #include <mesh/MeshFlatNodeBoundary.hpp>
 #include <mesh/MeshNodeBoundary.hpp>
+#include <mesh/MeshTraits.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <mesh/SubItemValuePerItemVariant.hpp>
 #include <scheme/DirichletBoundaryConditionDescriptor.hpp>
 #include <scheme/DiscreteFunctionP0.hpp>
@@ -39,9 +41,11 @@ acoustic_dt(const DiscreteFunctionP0<Dimension, const double>& c)
 double
 acoustic_dt(const std::shared_ptr<const DiscreteFunctionVariant>& c)
 {
-  std::shared_ptr mesh = getCommonMesh({c});
+  std::shared_ptr mesh_v = getCommonMesh({c});
 
-  switch (mesh->dimension()) {
+  const size_t mesh_dimension = std::visit([](auto&& mesh) { return mesh->dimension(); }, mesh_v->meshPointer());
+
+  switch (mesh_dimension) {
   case 1: {
     return acoustic_dt(c->get<DiscreteFunctionP0<1, const double>>());
   }
@@ -391,7 +395,7 @@ class AcousticSolverHandler::AcousticSolver final : public AcousticSolverHandler
       throw NormalError("acoustic solver expects P0 functions");
     }
 
-    const MeshType& mesh              = dynamic_cast<const MeshType&>(*i_mesh);
+    const MeshType& mesh              = *i_mesh->get<MeshType>();
     const DiscreteScalarFunction& rho = rho_v->get<DiscreteScalarFunction>();
     const DiscreteScalarFunction& c   = c_v->get<DiscreteScalarFunction>();
     const DiscreteVectorFunction& u   = u_v->get<DiscreteVectorFunction>();
@@ -416,7 +420,7 @@ class AcousticSolverHandler::AcousticSolver final : public AcousticSolverHandler
                            std::make_shared<const SubItemValuePerItemVariant>(Fjr));
   }
 
-  std::tuple<std::shared_ptr<const IMesh>,
+  std::tuple<std::shared_ptr<const MeshVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>>
@@ -468,12 +472,13 @@ class AcousticSolverHandler::AcousticSolver final : public AcousticSolverHandler
     parallel_for(
       mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { new_rho[j] *= Vj[j] / new_Vj[j]; });
 
-    return {new_mesh, std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_rho)),
+    return {std::make_shared<MeshVariant>(new_mesh),
+            std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_rho)),
             std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(new_mesh, new_u)),
             std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_E))};
   }
 
-  std::tuple<std::shared_ptr<const IMesh>,
+  std::tuple<std::shared_ptr<const MeshVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>>
@@ -493,16 +498,16 @@ class AcousticSolverHandler::AcousticSolver final : public AcousticSolverHandler
       throw NormalError("acoustic solver expects P0 functions");
     }
 
-    return this->apply_fluxes(dt,                                       //
-                              dynamic_cast<const MeshType&>(*i_mesh),   //
-                              rho_v->get<DiscreteScalarFunction>(),     //
-                              u_v->get<DiscreteVectorFunction>(),       //
-                              E_v->get<DiscreteScalarFunction>(),       //
-                              ur->get<NodeValue<const Rd>>(),           //
+    return this->apply_fluxes(dt,                                     //
+                              *i_mesh->get<MeshType>(),               //
+                              rho_v->get<DiscreteScalarFunction>(),   //
+                              u_v->get<DiscreteVectorFunction>(),     //
+                              E_v->get<DiscreteScalarFunction>(),     //
+                              ur->get<NodeValue<const Rd>>(),         //
                               Fjr->get<NodeValuePerCell<const Rd>>());
   }
 
-  std::tuple<std::shared_ptr<const IMesh>,
+  std::tuple<std::shared_ptr<const MeshVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>>
@@ -876,27 +881,20 @@ class AcousticSolverHandler::AcousticSolver<Dimension>::SymmetryBoundaryConditio
   ~SymmetryBoundaryCondition() = default;
 };
 
-AcousticSolverHandler::AcousticSolverHandler(const std::shared_ptr<const IMesh>& i_mesh)
+AcousticSolverHandler::AcousticSolverHandler(const std::shared_ptr<const MeshVariant>& i_mesh)
 {
   if (not i_mesh) {
     throw NormalError("discrete functions are not defined on the same mesh");
   }
 
-  switch (i_mesh->dimension()) {
-  case 1: {
-    m_acoustic_solver = std::make_unique<AcousticSolver<1>>();
-    break;
-  }
-  case 2: {
-    m_acoustic_solver = std::make_unique<AcousticSolver<2>>();
-    break;
-  }
-  case 3: {
-    m_acoustic_solver = std::make_unique<AcousticSolver<3>>();
-    break;
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  std::visit(
+    [&](auto&& mesh) {
+      using MeshType = typename std::decay_t<decltype(mesh)>::element_type;
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        m_acoustic_solver = std::make_unique<AcousticSolver<MeshType::Dimension>>();
+      } else {
+        throw NormalError("unexpected mesh type");
+      }
+    },
+    i_mesh->meshPointer());
 }
diff --git a/src/scheme/AcousticSolver.hpp b/src/scheme/AcousticSolver.hpp
index 36b62a32a..85d829c1b 100644
--- a/src/scheme/AcousticSolver.hpp
+++ b/src/scheme/AcousticSolver.hpp
@@ -7,7 +7,7 @@
 
 class DiscreteFunctionVariant;
 class IBoundaryConditionDescriptor;
-class IMesh;
+class MeshVariant;
 class ItemValueVariant;
 class SubItemValuePerItemVariant;
 
@@ -35,7 +35,7 @@ class AcousticSolverHandler
       const std::shared_ptr<const DiscreteFunctionVariant>& p,
       const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const = 0;
 
-    virtual std::tuple<std::shared_ptr<const IMesh>,
+    virtual std::tuple<std::shared_ptr<const MeshVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>>
@@ -46,7 +46,7 @@ class AcousticSolverHandler
                  const std::shared_ptr<const ItemValueVariant>& ur,
                  const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr) const = 0;
 
-    virtual std::tuple<std::shared_ptr<const IMesh>,
+    virtual std::tuple<std::shared_ptr<const MeshVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>>
@@ -78,7 +78,7 @@ class AcousticSolverHandler
     return *m_acoustic_solver;
   }
 
-  AcousticSolverHandler(const std::shared_ptr<const IMesh>& mesh);
+  AcousticSolverHandler(const std::shared_ptr<const MeshVariant>& mesh_v);
 };
 
 #endif   // ACOUSTIC_SOLVER_HPP
diff --git a/src/scheme/DiscreteFunctionIntegrator.cpp b/src/scheme/DiscreteFunctionIntegrator.cpp
index c77f7a2c8..5fd91f84a 100644
--- a/src/scheme/DiscreteFunctionIntegrator.cpp
+++ b/src/scheme/DiscreteFunctionIntegrator.cpp
@@ -2,20 +2,22 @@
 
 #include <language/utils/IntegrateCellValue.hpp>
 #include <mesh/MeshCellZone.hpp>
+#include <mesh/MeshTraits.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <scheme/DiscreteFunctionP0.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
 #include <utils/Exceptions.hpp>
 
-template <size_t Dimension, typename DataType, typename ValueType>
+template <typename MeshType, typename DataType, typename ValueType>
 DiscreteFunctionVariant
 DiscreteFunctionIntegrator::_integrateOnZoneList() const
 {
   static_assert(std::is_convertible_v<DataType, ValueType>);
   Assert(m_zone_list.size() > 0, "no zone list provided");
 
-  using MeshType = Mesh<Connectivity<Dimension>>;
+  constexpr size_t Dimension = MeshType::Dimension;
 
-  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(m_mesh);
+  std::shared_ptr p_mesh = m_mesh->get<MeshType>();
 
   CellValue<bool> is_in_zone{p_mesh->connectivity()};
   is_in_zone.fill(false);
@@ -65,34 +67,34 @@ DiscreteFunctionIntegrator::_integrateOnZoneList() const
   return DiscreteFunctionP0<Dimension, ValueType>(p_mesh, cell_value);
 }
 
-template <size_t Dimension, typename DataType, typename ValueType>
+template <typename MeshType, typename DataType, typename ValueType>
 DiscreteFunctionVariant
 DiscreteFunctionIntegrator::_integrateGlobally() const
 {
   Assert(m_zone_list.size() == 0, "invalid call when zones are defined");
 
-  using MeshType       = Mesh<Connectivity<Dimension>>;
-  std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(m_mesh);
+  std::shared_ptr mesh = m_mesh->get<MeshType>();
 
   static_assert(std::is_convertible_v<DataType, ValueType>);
 
-  return DiscreteFunctionP0<Dimension,
-                            ValueType>(mesh, IntegrateCellValue<ValueType(TinyVector<Dimension>)>::template integrate<
-                                               MeshType>(m_function_id, *m_quadrature_descriptor, *mesh));
+  return DiscreteFunctionP0<
+    MeshType::Dimension, ValueType>(mesh,
+                                    IntegrateCellValue<ValueType(TinyVector<MeshType::Dimension>)>::template integrate<
+                                      MeshType>(m_function_id, *m_quadrature_descriptor, *mesh));
 }
 
-template <size_t Dimension, typename DataType, typename ValueType>
+template <typename MeshType, typename DataType, typename ValueType>
 DiscreteFunctionVariant
 DiscreteFunctionIntegrator::_integrate() const
 {
   if (m_zone_list.size() == 0) {
-    return this->_integrateGlobally<Dimension, DataType, ValueType>();
+    return this->_integrateGlobally<MeshType, DataType, ValueType>();
   } else {
-    return this->_integrateOnZoneList<Dimension, DataType, ValueType>();
+    return this->_integrateOnZoneList<MeshType, DataType, ValueType>();
   }
 }
 
-template <size_t Dimension>
+template <typename MeshType>
 DiscreteFunctionVariant
 DiscreteFunctionIntegrator::_integrate() const
 {
@@ -103,27 +105,27 @@ DiscreteFunctionIntegrator::_integrate() const
 
   switch (data_type) {
   case ASTNodeDataType::bool_t: {
-    return this->_integrate<Dimension, bool, double>();
+    return this->_integrate<MeshType, bool, double>();
   }
   case ASTNodeDataType::unsigned_int_t: {
-    return this->_integrate<Dimension, uint64_t, double>();
+    return this->_integrate<MeshType, uint64_t, double>();
   }
   case ASTNodeDataType::int_t: {
-    return this->_integrate<Dimension, int64_t, double>();
+    return this->_integrate<MeshType, int64_t, double>();
   }
   case ASTNodeDataType::double_t: {
-    return this->_integrate<Dimension, double>();
+    return this->_integrate<MeshType, double>();
   }
   case ASTNodeDataType::vector_t: {
     switch (data_type.dimension()) {
     case 1: {
-      return this->_integrate<Dimension, TinyVector<1>>();
+      return this->_integrate<MeshType, TinyVector<1>>();
     }
     case 2: {
-      return this->_integrate<Dimension, TinyVector<2>>();
+      return this->_integrate<MeshType, TinyVector<2>>();
     }
     case 3: {
-      return this->_integrate<Dimension, TinyVector<3>>();
+      return this->_integrate<MeshType, TinyVector<3>>();
     }
       // LCOV_EXCL_START
     default: {
@@ -139,13 +141,13 @@ DiscreteFunctionIntegrator::_integrate() const
     Assert(data_type.numberOfColumns() == data_type.numberOfRows(), "undefined matrix type");
     switch (data_type.numberOfColumns()) {
     case 1: {
-      return this->_integrate<Dimension, TinyMatrix<1>>();
+      return this->_integrate<MeshType, TinyMatrix<1>>();
     }
     case 2: {
-      return this->_integrate<Dimension, TinyMatrix<2>>();
+      return this->_integrate<MeshType, TinyMatrix<2>>();
     }
     case 3: {
-      return this->_integrate<Dimension, TinyMatrix<3>>();
+      return this->_integrate<MeshType, TinyMatrix<3>>();
     }
       // LCOV_EXCL_START
     default: {
@@ -171,20 +173,13 @@ DiscreteFunctionIntegrator::_integrate() const
 DiscreteFunctionVariant
 DiscreteFunctionIntegrator::integrate() const
 {
-  switch (m_mesh->dimension()) {
-  case 1: {
-    return this->_integrate<1>();
-  }
-  case 2: {
-    return this->_integrate<2>();
-  }
-  case 3: {
-    return this->_integrate<3>();
-  }
-    // LCOV_EXCL_START
-  default: {
-    throw UnexpectedError("invalid dimension");
-  }
-    // LCOV_EXCL_STOP
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      using MeshType = typename std::decay_t<decltype(mesh)>::element_type;
+
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        return this->_integrate<MeshType>();
+      }
+    },
+    m_mesh->meshPointer());
 }
diff --git a/src/scheme/DiscreteFunctionIntegrator.hpp b/src/scheme/DiscreteFunctionIntegrator.hpp
index e21beabf7..b832ee6f4 100644
--- a/src/scheme/DiscreteFunctionIntegrator.hpp
+++ b/src/scheme/DiscreteFunctionIntegrator.hpp
@@ -3,43 +3,43 @@
 
 #include <analysis/IQuadratureDescriptor.hpp>
 #include <language/utils/FunctionSymbolId.hpp>
-#include <mesh/IMesh.hpp>
 #include <mesh/IZoneDescriptor.hpp>
 
 #include <memory>
 
 class DiscreteFunctionVariant;
+class MeshVariant;
 
 class DiscreteFunctionIntegrator
 {
  private:
-  std::shared_ptr<const IMesh> m_mesh;
+  std::shared_ptr<const MeshVariant> m_mesh;
   const std::vector<std::shared_ptr<const IZoneDescriptor>> m_zone_list;
   std::shared_ptr<const IQuadratureDescriptor> m_quadrature_descriptor;
   const FunctionSymbolId m_function_id;
 
-  template <size_t Dimension, typename DataType, typename ValueType = DataType>
+  template <typename MeshType, typename DataType, typename ValueType = DataType>
   DiscreteFunctionVariant _integrateOnZoneList() const;
 
-  template <size_t Dimension, typename DataType, typename ValueType = DataType>
+  template <typename MeshType, typename DataType, typename ValueType = DataType>
   DiscreteFunctionVariant _integrateGlobally() const;
 
-  template <size_t Dimension, typename DataType, typename ValueType = DataType>
+  template <typename MeshType, typename DataType, typename ValueType = DataType>
   DiscreteFunctionVariant _integrate() const;
 
-  template <size_t Dimension>
+  template <typename MeshType>
   DiscreteFunctionVariant _integrate() const;
 
  public:
   DiscreteFunctionVariant integrate() const;
 
-  DiscreteFunctionIntegrator(const std::shared_ptr<const IMesh>& mesh,
+  DiscreteFunctionIntegrator(const std::shared_ptr<const MeshVariant>& mesh,
                              const std::shared_ptr<const IQuadratureDescriptor>& quadrature_descriptor,
                              const FunctionSymbolId& function_id)
     : m_mesh{mesh}, m_quadrature_descriptor{quadrature_descriptor}, m_function_id{function_id}
   {}
 
-  DiscreteFunctionIntegrator(const std::shared_ptr<const IMesh>& mesh,
+  DiscreteFunctionIntegrator(const std::shared_ptr<const MeshVariant>& mesh,
                              const std::vector<std::shared_ptr<const IZoneDescriptor>>& zone_list,
                              const std::shared_ptr<const IQuadratureDescriptor>& quadrature_descriptor,
                              const FunctionSymbolId& function_id)
diff --git a/src/scheme/DiscreteFunctionInterpoler.cpp b/src/scheme/DiscreteFunctionInterpoler.cpp
index c570e67e5..00e6ebabe 100644
--- a/src/scheme/DiscreteFunctionInterpoler.cpp
+++ b/src/scheme/DiscreteFunctionInterpoler.cpp
@@ -2,18 +2,21 @@
 
 #include <language/utils/InterpolateItemValue.hpp>
 #include <mesh/MeshCellZone.hpp>
+#include <mesh/MeshTraits.hpp>
 #include <scheme/DiscreteFunctionP0.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
 #include <utils/Exceptions.hpp>
 
-template <size_t Dimension, typename DataType, typename ValueType>
+template <typename MeshType, typename DataType, typename ValueType>
 DiscreteFunctionVariant
 DiscreteFunctionInterpoler::_interpolateOnZoneList() const
 {
   static_assert(std::is_convertible_v<DataType, ValueType>);
   Assert(m_zone_list.size() > 0, "no zone list provided");
 
-  std::shared_ptr p_mesh  = std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(m_mesh);
+  constexpr size_t Dimension = MeshType::Dimension;
+
+  std::shared_ptr p_mesh  = m_mesh->get<MeshType>();
   using MeshDataType      = MeshData<Dimension>;
   MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*p_mesh);
 
@@ -65,13 +68,14 @@ DiscreteFunctionInterpoler::_interpolateOnZoneList() const
   return DiscreteFunctionP0<Dimension, ValueType>(p_mesh, cell_value);
 }
 
-template <size_t Dimension, typename DataType, typename ValueType>
+template <typename MeshType, typename DataType, typename ValueType>
 DiscreteFunctionVariant
 DiscreteFunctionInterpoler::_interpolateGlobally() const
 {
   Assert(m_zone_list.size() == 0, "invalid call when zones are defined");
+  constexpr size_t Dimension = MeshType::Dimension;
 
-  std::shared_ptr p_mesh  = std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(m_mesh);
+  std::shared_ptr p_mesh  = m_mesh->get<MeshType>();
   using MeshDataType      = MeshData<Dimension>;
   MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*p_mesh);
 
@@ -95,18 +99,18 @@ DiscreteFunctionInterpoler::_interpolateGlobally() const
   }
 }
 
-template <size_t Dimension, typename DataType, typename ValueType>
+template <typename MeshType, typename DataType, typename ValueType>
 DiscreteFunctionVariant
 DiscreteFunctionInterpoler::_interpolate() const
 {
   if (m_zone_list.size() == 0) {
-    return this->_interpolateGlobally<Dimension, DataType, ValueType>();
+    return this->_interpolateGlobally<MeshType, DataType, ValueType>();
   } else {
-    return this->_interpolateOnZoneList<Dimension, DataType, ValueType>();
+    return this->_interpolateOnZoneList<MeshType, DataType, ValueType>();
   }
 }
 
-template <size_t Dimension>
+template <typename MeshType>
 DiscreteFunctionVariant
 DiscreteFunctionInterpoler::_interpolate() const
 {
@@ -117,27 +121,27 @@ DiscreteFunctionInterpoler::_interpolate() const
 
   switch (data_type) {
   case ASTNodeDataType::bool_t: {
-    return this->_interpolate<Dimension, bool, double>();
+    return this->_interpolate<MeshType, bool, double>();
   }
   case ASTNodeDataType::unsigned_int_t: {
-    return this->_interpolate<Dimension, uint64_t, double>();
+    return this->_interpolate<MeshType, uint64_t, double>();
   }
   case ASTNodeDataType::int_t: {
-    return this->_interpolate<Dimension, int64_t, double>();
+    return this->_interpolate<MeshType, int64_t, double>();
   }
   case ASTNodeDataType::double_t: {
-    return this->_interpolate<Dimension, double>();
+    return this->_interpolate<MeshType, double>();
   }
   case ASTNodeDataType::vector_t: {
     switch (data_type.dimension()) {
     case 1: {
-      return this->_interpolate<Dimension, TinyVector<1>>();
+      return this->_interpolate<MeshType, TinyVector<1>>();
     }
     case 2: {
-      return this->_interpolate<Dimension, TinyVector<2>>();
+      return this->_interpolate<MeshType, TinyVector<2>>();
     }
     case 3: {
-      return this->_interpolate<Dimension, TinyVector<3>>();
+      return this->_interpolate<MeshType, TinyVector<3>>();
     }
       // LCOV_EXCL_START
     default: {
@@ -153,13 +157,13 @@ DiscreteFunctionInterpoler::_interpolate() const
     Assert(data_type.numberOfColumns() == data_type.numberOfRows(), "undefined matrix type");
     switch (data_type.numberOfColumns()) {
     case 1: {
-      return this->_interpolate<Dimension, TinyMatrix<1>>();
+      return this->_interpolate<MeshType, TinyMatrix<1>>();
     }
     case 2: {
-      return this->_interpolate<Dimension, TinyMatrix<2>>();
+      return this->_interpolate<MeshType, TinyMatrix<2>>();
     }
     case 3: {
-      return this->_interpolate<Dimension, TinyMatrix<3>>();
+      return this->_interpolate<MeshType, TinyMatrix<3>>();
     }
       // LCOV_EXCL_START
     default: {
@@ -185,20 +189,13 @@ DiscreteFunctionInterpoler::_interpolate() const
 DiscreteFunctionVariant
 DiscreteFunctionInterpoler::interpolate() const
 {
-  switch (m_mesh->dimension()) {
-  case 1: {
-    return this->_interpolate<1>();
-  }
-  case 2: {
-    return this->_interpolate<2>();
-  }
-  case 3: {
-    return this->_interpolate<3>();
-  }
-    // LCOV_EXCL_START
-  default: {
-    throw UnexpectedError("invalid dimension");
-  }
-    // LCOV_EXCL_STOP
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      using MeshType = typename std::decay_t<decltype(mesh)>::element_type;
+
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        return this->_interpolate<MeshType>();
+      }
+    },
+    m_mesh->meshPointer());
 }
diff --git a/src/scheme/DiscreteFunctionInterpoler.hpp b/src/scheme/DiscreteFunctionInterpoler.hpp
index 0f436d43c..73c3e55f2 100644
--- a/src/scheme/DiscreteFunctionInterpoler.hpp
+++ b/src/scheme/DiscreteFunctionInterpoler.hpp
@@ -2,44 +2,44 @@
 #define DISCRETE_FUNCTION_INTERPOLER_HPP
 
 #include <language/utils/FunctionSymbolId.hpp>
-#include <mesh/IMesh.hpp>
 #include <mesh/IZoneDescriptor.hpp>
 #include <scheme/IDiscreteFunctionDescriptor.hpp>
 
 class DiscreteFunctionVariant;
+class MeshVariant;
 
 #include <memory>
 
 class DiscreteFunctionInterpoler
 {
  private:
-  std::shared_ptr<const IMesh> m_mesh;
+  std::shared_ptr<const MeshVariant> m_mesh;
   const std::vector<std::shared_ptr<const IZoneDescriptor>> m_zone_list;
   std::shared_ptr<const IDiscreteFunctionDescriptor> m_discrete_function_descriptor;
   const FunctionSymbolId m_function_id;
 
-  template <size_t Dimension, typename DataType, typename ValueType = DataType>
+  template <typename MeshType, typename DataType, typename ValueType = DataType>
   DiscreteFunctionVariant _interpolateOnZoneList() const;
 
-  template <size_t Dimension, typename DataType, typename ValueType = DataType>
+  template <typename MeshType, typename DataType, typename ValueType = DataType>
   DiscreteFunctionVariant _interpolateGlobally() const;
 
-  template <size_t Dimension, typename DataType, typename ValueType = DataType>
+  template <typename MeshType, typename DataType, typename ValueType = DataType>
   DiscreteFunctionVariant _interpolate() const;
 
-  template <size_t Dimension>
+  template <typename MeshType>
   DiscreteFunctionVariant _interpolate() const;
 
  public:
   DiscreteFunctionVariant interpolate() const;
 
-  DiscreteFunctionInterpoler(const std::shared_ptr<const IMesh>& mesh,
+  DiscreteFunctionInterpoler(const std::shared_ptr<const MeshVariant>& mesh,
                              const std::shared_ptr<const IDiscreteFunctionDescriptor>& discrete_function_descriptor,
                              const FunctionSymbolId& function_id)
     : m_mesh{mesh}, m_discrete_function_descriptor{discrete_function_descriptor}, m_function_id{function_id}
   {}
 
-  DiscreteFunctionInterpoler(const std::shared_ptr<const IMesh>& mesh,
+  DiscreteFunctionInterpoler(const std::shared_ptr<const MeshVariant>& mesh,
                              const std::vector<std::shared_ptr<const IZoneDescriptor>>& zone_list,
                              const std::shared_ptr<const IDiscreteFunctionDescriptor>& discrete_function_descriptor,
                              const FunctionSymbolId& function_id)
diff --git a/src/scheme/DiscreteFunctionP0.hpp b/src/scheme/DiscreteFunctionP0.hpp
index 5a49b9db3..0e11b608a 100644
--- a/src/scheme/DiscreteFunctionP0.hpp
+++ b/src/scheme/DiscreteFunctionP0.hpp
@@ -8,6 +8,7 @@
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshData.hpp>
 #include <mesh/MeshDataManager.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <scheme/DiscreteFunctionDescriptorP0.hpp>
 
 template <size_t Dimension, typename DataType>
@@ -42,7 +43,7 @@ class DiscreteFunctionP0
   }
 
   PUGS_INLINE
-  std::shared_ptr<const IMesh>
+  std::shared_ptr<const MeshType>
   mesh() const
   {
     return m_mesh;
diff --git a/src/scheme/DiscreteFunctionP0Vector.hpp b/src/scheme/DiscreteFunctionP0Vector.hpp
index 7bd833f34..7801626a4 100644
--- a/src/scheme/DiscreteFunctionP0Vector.hpp
+++ b/src/scheme/DiscreteFunctionP0Vector.hpp
@@ -52,7 +52,7 @@ class DiscreteFunctionP0Vector
   }
 
   PUGS_INLINE
-  std::shared_ptr<const IMesh>
+  std::shared_ptr<const MeshType>
   mesh() const
   {
     return m_mesh;
diff --git a/src/scheme/DiscreteFunctionUtils.cpp b/src/scheme/DiscreteFunctionUtils.cpp
index ba2416a9a..df39bbcea 100644
--- a/src/scheme/DiscreteFunctionUtils.cpp
+++ b/src/scheme/DiscreteFunctionUtils.cpp
@@ -1,65 +1,87 @@
 #include <scheme/DiscreteFunctionUtils.hpp>
 
 #include <mesh/Connectivity.hpp>
-#include <mesh/IMesh.hpp>
 #include <mesh/Mesh.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <scheme/DiscreteFunctionP0.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
 #include <utils/Stringify.hpp>
 
-std::shared_ptr<const IMesh>
+std::shared_ptr<const MeshVariant>
 getCommonMesh(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list)
 {
-  std::shared_ptr<const IMesh> i_mesh;
+  std::optional<size_t> mesh_id;
+  std::shared_ptr<const MeshVariant> mesh_v;
   bool is_same_mesh = true;
   for (const auto& discrete_function_variant : discrete_function_variant_list) {
     std::visit(
       [&](auto&& discrete_function) {
-        if (not i_mesh.use_count()) {
-          i_mesh = discrete_function.mesh();
+        if (not mesh_id.has_value()) {
+          mesh_v  = std::make_shared<MeshVariant>(discrete_function.mesh());
+          mesh_id = discrete_function.mesh()->id();
         } else {
-          if (i_mesh != discrete_function.mesh()) {
+          if (mesh_id != discrete_function.mesh()->id()) {
             is_same_mesh = false;
+            mesh_v.reset();
           }
         }
       },
       discrete_function_variant->discreteFunction());
   }
-  if (not is_same_mesh) {
-    i_mesh.reset();
-  }
-  return i_mesh;
+
+  return mesh_v;
 }
 
 bool
 hasSameMesh(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list)
 {
-  std::shared_ptr<const IMesh> i_mesh;
-  bool is_same_mesh = true;
+  std::optional<size_t> mesh_id;
+
+  bool same_mesh = true;
   for (const auto& discrete_function_variant : discrete_function_variant_list) {
     std::visit(
       [&](auto&& discrete_function) {
-        if (not i_mesh.use_count()) {
-          i_mesh = discrete_function.mesh();
+        if (not mesh_id.has_value()) {
+          mesh_id = discrete_function.mesh()->id();
         } else {
-          if (i_mesh != discrete_function.mesh()) {
-            is_same_mesh = false;
+          if (mesh_id != discrete_function.mesh()->id()) {
+            same_mesh = false;
           }
         }
       },
       discrete_function_variant->discreteFunction());
   }
 
-  return is_same_mesh;
+  return same_mesh;
+}
+
+bool
+hasSameMesh(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list,
+            const std::shared_ptr<const MeshVariant>& mesh_v)
+{
+  const size_t mesh_id = mesh_v->id();
+
+  bool same_mesh = true;
+  for (const auto& discrete_function_variant : discrete_function_variant_list) {
+    std::visit(
+      [&](auto&& discrete_function) {
+        if (mesh_id != discrete_function.mesh()->id()) {
+          same_mesh = false;
+        }
+      },
+      discrete_function_variant->discreteFunction());
+  }
+
+  return same_mesh;
 }
 
 template <typename MeshType, typename DiscreteFunctionT>
 std::shared_ptr<const DiscreteFunctionVariant>
 shallowCopy(const std::shared_ptr<const MeshType>& mesh, const DiscreteFunctionT& f)
 {
-  const std::shared_ptr function_mesh = std::dynamic_pointer_cast<const MeshType>(f.mesh());
+  const size_t function_connectivity_id = f.mesh()->shared_connectivity()->id();
 
-  if (mesh->shared_connectivity() != function_mesh->shared_connectivity()) {
+  if (mesh->shared_connectivity()->id() != function_connectivity_id) {
     throw NormalError("cannot shallow copy when connectivity changes");
   }
 
@@ -77,33 +99,20 @@ shallowCopy(const std::shared_ptr<const MeshType>& mesh, const DiscreteFunctionT
 }
 
 std::shared_ptr<const DiscreteFunctionVariant>
-shallowCopy(const std::shared_ptr<const IMesh>& mesh,
+shallowCopy(const std::shared_ptr<const MeshVariant>& mesh_v,
             const std::shared_ptr<const DiscreteFunctionVariant>& discrete_function_variant)
 {
   return std::visit(
     [&](auto&& f) {
-      if (mesh == f.mesh()) {
+      const size_t mesh_id        = std::visit([](auto&& mesh) { return mesh->id(); }, mesh_v->meshPointer());
+      const size_t mesh_dimension = std::visit([](auto&& mesh) { return mesh->dimension(); }, mesh_v->meshPointer());
+      if (mesh_id == f.mesh()->id()) {
         return discrete_function_variant;
-      } else if (mesh->dimension() != f.mesh()->dimension()) {
+      } else if (mesh_dimension != f.mesh()->dimension()) {
         throw NormalError("incompatible mesh dimensions");
       }
 
-      switch (mesh->dimension()) {
-      case 1: {
-        return shallowCopy(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), f);
-      }
-      case 2: {
-        return shallowCopy(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), f);
-      }
-      case 3: {
-        return shallowCopy(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), f);
-      }
-        // LCOV_EXCL_START
-      default: {
-        throw UnexpectedError("invalid mesh dimension");
-      }
-        // LCOV_EXCL_STOP
-      }
+      return std::visit([&](auto&& mesh) { return shallowCopy(mesh, f); }, mesh_v->meshPointer());
     },
     discrete_function_variant->discreteFunction());
 }
diff --git a/src/scheme/DiscreteFunctionUtils.hpp b/src/scheme/DiscreteFunctionUtils.hpp
index 91acbccb7..865eaa213 100644
--- a/src/scheme/DiscreteFunctionUtils.hpp
+++ b/src/scheme/DiscreteFunctionUtils.hpp
@@ -21,13 +21,16 @@ checkDiscretizationType(const std::vector<std::shared_ptr<const DiscreteFunction
   return true;
 }
 
-std::shared_ptr<const IMesh> getCommonMesh(
+std::shared_ptr<const MeshVariant> getCommonMesh(
   const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list);
 
 bool hasSameMesh(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list);
 
+bool hasSameMesh(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list,
+                 const std::shared_ptr<const MeshVariant>& mesh_v);
+
 std::shared_ptr<const DiscreteFunctionVariant> shallowCopy(
-  const std::shared_ptr<const IMesh>& mesh,
+  const std::shared_ptr<const MeshVariant>& mesh_v,
   const std::shared_ptr<const DiscreteFunctionVariant>& discrete_function);
 
 #endif   // DISCRETE_FUNCTION_UTILS_HPP
diff --git a/src/scheme/DiscreteFunctionVectorIntegrator.cpp b/src/scheme/DiscreteFunctionVectorIntegrator.cpp
index 80b9e711e..f4722ab42 100644
--- a/src/scheme/DiscreteFunctionVectorIntegrator.cpp
+++ b/src/scheme/DiscreteFunctionVectorIntegrator.cpp
@@ -2,17 +2,19 @@
 
 #include <language/utils/IntegrateCellArray.hpp>
 #include <mesh/MeshCellZone.hpp>
+#include <mesh/MeshTraits.hpp>
 #include <scheme/DiscreteFunctionP0Vector.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
 #include <utils/Exceptions.hpp>
 
-template <size_t Dimension, typename DataType>
+template <typename MeshType, typename DataType>
 DiscreteFunctionVariant
 DiscreteFunctionVectorIntegrator::_integrateOnZoneList() const
 {
   Assert(m_zone_list.size() > 0, "no zone list provided");
+  constexpr size_t Dimension = MeshType::Dimension;
 
-  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(m_mesh);
+  std::shared_ptr p_mesh = m_mesh->get<MeshType>();
 
   CellValue<bool> is_in_zone{p_mesh->connectivity()};
   is_in_zone.fill(false);
@@ -66,31 +68,32 @@ DiscreteFunctionVectorIntegrator::_integrateOnZoneList() const
   return DiscreteFunctionP0Vector<Dimension, DataType>(p_mesh, cell_array);
 }
 
-template <size_t Dimension, typename DataType>
+template <typename MeshType, typename DataType>
 DiscreteFunctionVariant
 DiscreteFunctionVectorIntegrator::_integrateGlobally() const
 {
   Assert(m_zone_list.size() == 0, "invalid call when zones are defined");
 
-  std::shared_ptr mesh = std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(m_mesh);
+  std::shared_ptr mesh       = m_mesh->get<MeshType>();
+  constexpr size_t Dimension = MeshType::Dimension;
 
   return DiscreteFunctionP0Vector<Dimension, DataType>(mesh, IntegrateCellArray<DataType(TinyVector<Dimension>)>::
                                                                template integrate(m_function_id_list,
                                                                                   *m_quadrature_descriptor, *mesh));
 }
 
-template <size_t Dimension, typename DataType>
+template <typename MeshType, typename DataType>
 DiscreteFunctionVariant
 DiscreteFunctionVectorIntegrator::_integrate() const
 {
   if (m_zone_list.size() == 0) {
-    return this->_integrateGlobally<Dimension, DataType>();
+    return this->_integrateGlobally<MeshType, DataType>();
   } else {
-    return this->_integrateOnZoneList<Dimension, DataType>();
+    return this->_integrateOnZoneList<MeshType, DataType>();
   }
 }
 
-template <size_t Dimension>
+template <typename MeshType>
 DiscreteFunctionVariant
 DiscreteFunctionVectorIntegrator::_integrate() const
 {
@@ -114,7 +117,7 @@ DiscreteFunctionVectorIntegrator::_integrate() const
     }
     }
   }
-  return this->_integrate<Dimension, double>();
+  return this->_integrate<MeshType, double>();
 }
 
 DiscreteFunctionVariant
@@ -124,20 +127,13 @@ DiscreteFunctionVectorIntegrator::integrate() const
     throw NormalError("invalid discrete function type for vector integration");
   }
 
-  switch (m_mesh->dimension()) {
-  case 1: {
-    return this->_integrate<1>();
-  }
-  case 2: {
-    return this->_integrate<2>();
-  }
-  case 3: {
-    return this->_integrate<3>();
-  }
-    // LCOV_EXCL_START
-  default: {
-    throw UnexpectedError("invalid dimension");
-  }
-    // LCOV_EXCL_STOP
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      using MeshType = typename std::decay_t<decltype(mesh)>::element_type;
+
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        return this->_integrate<MeshType>();
+      }
+    },
+    m_mesh->meshPointer());
 }
diff --git a/src/scheme/DiscreteFunctionVectorIntegrator.hpp b/src/scheme/DiscreteFunctionVectorIntegrator.hpp
index 44b192bc9..e89943cfb 100644
--- a/src/scheme/DiscreteFunctionVectorIntegrator.hpp
+++ b/src/scheme/DiscreteFunctionVectorIntegrator.hpp
@@ -3,7 +3,6 @@
 
 #include <analysis/IQuadratureDescriptor.hpp>
 #include <language/utils/FunctionSymbolId.hpp>
-#include <mesh/IMesh.hpp>
 #include <mesh/IZoneDescriptor.hpp>
 #include <scheme/IDiscreteFunctionDescriptor.hpp>
 
@@ -11,33 +10,34 @@
 #include <vector>
 
 class DiscreteFunctionVariant;
+class MeshVariant;
 
 class DiscreteFunctionVectorIntegrator
 {
  private:
-  std::shared_ptr<const IMesh> m_mesh;
+  std::shared_ptr<const MeshVariant> m_mesh;
   const std::vector<std::shared_ptr<const IZoneDescriptor>> m_zone_list;
   std::shared_ptr<const IQuadratureDescriptor> m_quadrature_descriptor;
   std::shared_ptr<const IDiscreteFunctionDescriptor> m_discrete_function_descriptor;
   const std::vector<FunctionSymbolId> m_function_id_list;
 
-  template <size_t Dimension, typename DataType>
+  template <typename MeshType, typename DataType>
   DiscreteFunctionVariant _integrateOnZoneList() const;
 
-  template <size_t Dimension, typename DataType>
+  template <typename MeshType, typename DataType>
   DiscreteFunctionVariant _integrateGlobally() const;
 
-  template <size_t Dimension, typename DataType>
+  template <typename MeshType, typename DataType>
   DiscreteFunctionVariant _integrate() const;
 
-  template <size_t Dimension>
+  template <typename MeshType>
   DiscreteFunctionVariant _integrate() const;
 
  public:
   DiscreteFunctionVariant integrate() const;
 
   DiscreteFunctionVectorIntegrator(
-    const std::shared_ptr<const IMesh>& mesh,
+    const std::shared_ptr<const MeshVariant>& mesh,
     const std::shared_ptr<const IQuadratureDescriptor>& quadrature_descriptor,
     const std::shared_ptr<const IDiscreteFunctionDescriptor>& discrete_function_descriptor,
     const std::vector<FunctionSymbolId>& function_id_list)
@@ -48,7 +48,7 @@ class DiscreteFunctionVectorIntegrator
   {}
 
   DiscreteFunctionVectorIntegrator(
-    const std::shared_ptr<const IMesh>& mesh,
+    const std::shared_ptr<const MeshVariant>& mesh,
     const std::vector<std::shared_ptr<const IZoneDescriptor>>& zone_list,
     const std::shared_ptr<const IQuadratureDescriptor>& quadrature_descriptor,
     const std::shared_ptr<const IDiscreteFunctionDescriptor>& discrete_function_descriptor,
diff --git a/src/scheme/DiscreteFunctionVectorInterpoler.cpp b/src/scheme/DiscreteFunctionVectorInterpoler.cpp
index 57724b772..b9bd7b7d0 100644
--- a/src/scheme/DiscreteFunctionVectorInterpoler.cpp
+++ b/src/scheme/DiscreteFunctionVectorInterpoler.cpp
@@ -2,17 +2,19 @@
 
 #include <language/utils/InterpolateItemArray.hpp>
 #include <mesh/MeshCellZone.hpp>
+#include <mesh/MeshTraits.hpp>
 #include <scheme/DiscreteFunctionP0Vector.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
 #include <utils/Exceptions.hpp>
 
-template <size_t Dimension, typename DataType>
+template <typename MeshType, typename DataType>
 DiscreteFunctionVariant
 DiscreteFunctionVectorInterpoler::_interpolateOnZoneList() const
 {
   Assert(m_zone_list.size() > 0, "no zone list provided");
+  constexpr size_t Dimension = MeshType::Dimension;
 
-  std::shared_ptr p_mesh  = std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(m_mesh);
+  std::shared_ptr p_mesh  = m_mesh->get<MeshType>();
   using MeshDataType      = MeshData<Dimension>;
   MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*p_mesh);
 
@@ -64,13 +66,14 @@ DiscreteFunctionVectorInterpoler::_interpolateOnZoneList() const
   return DiscreteFunctionP0Vector<Dimension, DataType>(p_mesh, cell_array);
 }
 
-template <size_t Dimension, typename DataType>
+template <typename MeshType, typename DataType>
 DiscreteFunctionVariant
 DiscreteFunctionVectorInterpoler::_interpolateGlobally() const
 {
   Assert(m_zone_list.size() == 0, "invalid call when zones are defined");
+  constexpr size_t Dimension = MeshType::Dimension;
 
-  std::shared_ptr p_mesh = std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(m_mesh);
+  std::shared_ptr p_mesh = m_mesh->get<MeshType>();
 
   using MeshDataType      = MeshData<Dimension>;
   MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*p_mesh);
@@ -81,18 +84,18 @@ DiscreteFunctionVectorInterpoler::_interpolateGlobally() const
                                                                                               mesh_data.xj()));
 }
 
-template <size_t Dimension, typename DataType>
+template <typename MeshType, typename DataType>
 DiscreteFunctionVariant
 DiscreteFunctionVectorInterpoler::_interpolate() const
 {
   if (m_zone_list.size() == 0) {
-    return this->_interpolateGlobally<Dimension, DataType>();
+    return this->_interpolateGlobally<MeshType, DataType>();
   } else {
-    return this->_interpolateOnZoneList<Dimension, DataType>();
+    return this->_interpolateOnZoneList<MeshType, DataType>();
   }
 }
 
-template <size_t Dimension>
+template <typename MeshType>
 DiscreteFunctionVariant
 DiscreteFunctionVectorInterpoler::_interpolate() const
 {
@@ -137,7 +140,7 @@ DiscreteFunctionVectorInterpoler::_interpolate() const
     }
   }
 
-  return this->_interpolate<Dimension, double>();
+  return this->_interpolate<MeshType, double>();
 }
 
 DiscreteFunctionVariant
@@ -147,20 +150,13 @@ DiscreteFunctionVectorInterpoler::interpolate() const
     throw NormalError("invalid discrete function type for vector interpolation");
   }
 
-  switch (m_mesh->dimension()) {
-  case 1: {
-    return this->_interpolate<1>();
-  }
-  case 2: {
-    return this->_interpolate<2>();
-  }
-  case 3: {
-    return this->_interpolate<3>();
-  }
-    // LCOV_EXCL_START
-  default: {
-    throw UnexpectedError("invalid dimension");
-  }
-    // LCOV_EXCL_STOP
-  }
+  return std::visit(
+    [&](auto&& mesh) {
+      using MeshType = typename std::decay_t<decltype(mesh)>::element_type;
+
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        return this->_interpolate<MeshType>();
+      }
+    },
+    m_mesh->meshPointer());
 }
diff --git a/src/scheme/DiscreteFunctionVectorInterpoler.hpp b/src/scheme/DiscreteFunctionVectorInterpoler.hpp
index 8cec9d09e..2999f1220 100644
--- a/src/scheme/DiscreteFunctionVectorInterpoler.hpp
+++ b/src/scheme/DiscreteFunctionVectorInterpoler.hpp
@@ -2,11 +2,11 @@
 #define DISCRETE_FUNCTION_VECTOR_INTERPOLER_HPP
 
 #include <language/utils/FunctionSymbolId.hpp>
-#include <mesh/IMesh.hpp>
 #include <mesh/IZoneDescriptor.hpp>
 #include <scheme/IDiscreteFunctionDescriptor.hpp>
 
 class DiscreteFunctionVariant;
+class MeshVariant;
 
 #include <memory>
 #include <vector>
@@ -14,35 +14,35 @@ class DiscreteFunctionVariant;
 class DiscreteFunctionVectorInterpoler
 {
  private:
-  std::shared_ptr<const IMesh> m_mesh;
+  std::shared_ptr<const MeshVariant> m_mesh;
   const std::vector<std::shared_ptr<const IZoneDescriptor>> m_zone_list;
   std::shared_ptr<const IDiscreteFunctionDescriptor> m_discrete_function_descriptor;
   const std::vector<FunctionSymbolId> m_function_id_list;
 
-  template <size_t Dimension, typename DataType>
+  template <typename MeshType, typename DataType>
   DiscreteFunctionVariant _interpolateOnZoneList() const;
 
-  template <size_t Dimension, typename DataType>
+  template <typename MeshType, typename DataType>
   DiscreteFunctionVariant _interpolateGlobally() const;
 
-  template <size_t Dimension, typename DataType>
+  template <typename MeshType, typename DataType>
   DiscreteFunctionVariant _interpolate() const;
 
-  template <size_t Dimension>
+  template <typename MeshType>
   DiscreteFunctionVariant _interpolate() const;
 
  public:
   DiscreteFunctionVariant interpolate() const;
 
   DiscreteFunctionVectorInterpoler(
-    const std::shared_ptr<const IMesh>& mesh,
+    const std::shared_ptr<const MeshVariant>& mesh,
     const std::shared_ptr<const IDiscreteFunctionDescriptor>& discrete_function_descriptor,
     const std::vector<FunctionSymbolId>& function_id_list)
     : m_mesh{mesh}, m_discrete_function_descriptor{discrete_function_descriptor}, m_function_id_list{function_id_list}
   {}
 
   DiscreteFunctionVectorInterpoler(
-    const std::shared_ptr<const IMesh>& mesh,
+    const std::shared_ptr<const MeshVariant>& mesh,
     const std::vector<std::shared_ptr<const IZoneDescriptor>>& zone_list,
     const std::shared_ptr<const IDiscreteFunctionDescriptor>& discrete_function_descriptor,
     const std::vector<FunctionSymbolId>& function_id_list)
diff --git a/src/scheme/FluxingAdvectionSolver.cpp b/src/scheme/FluxingAdvectionSolver.cpp
index 754c6e3ac..01ff407bd 100644
--- a/src/scheme/FluxingAdvectionSolver.cpp
+++ b/src/scheme/FluxingAdvectionSolver.cpp
@@ -7,7 +7,6 @@
 #include <language/utils/InterpolateItemArray.hpp>
 #include <language/utils/InterpolateItemValue.hpp>
 #include <mesh/Connectivity.hpp>
-#include <mesh/IMesh.hpp>
 #include <mesh/ItemArrayUtils.hpp>
 #include <mesh/ItemValueUtils.hpp>
 #include <mesh/Mesh.hpp>
@@ -192,9 +191,9 @@ class FluxingAdvectionSolver
   std::vector<std::shared_ptr<const DiscreteFunctionVariant>>   //
   remap(const std::vector<std::shared_ptr<const VariableBCDescriptor>>& quantity_list_with_bc);
 
-  FluxingAdvectionSolver(const std::shared_ptr<const IMesh> i_old_mesh, const std::shared_ptr<const IMesh> i_new_mesh)
-    : m_old_mesh{std::dynamic_pointer_cast<const MeshType>(i_old_mesh)},
-      m_new_mesh{std::dynamic_pointer_cast<const MeshType>(i_new_mesh)}
+  FluxingAdvectionSolver(const std::shared_ptr<const MeshType>& i_old_mesh,
+                         const std::shared_ptr<const MeshType>& i_new_mesh)
+    : m_old_mesh{i_old_mesh}, m_new_mesh{i_new_mesh}
   {
     if ((m_old_mesh.use_count() == 0) or (m_new_mesh.use_count() == 0)) {
       throw NormalError("old and new meshes must be of same type");
@@ -865,7 +864,7 @@ class FluxingAdvectionSolver<Dimension>::SymmetryBoundaryCondition
 };
 
 std::vector<std::shared_ptr<const DiscreteFunctionVariant>>
-advectByFluxing(const std::shared_ptr<const IMesh> i_new_mesh,
+advectByFluxing(const std::shared_ptr<const MeshVariant> new_mesh_v,
                 const std::vector<std::shared_ptr<const VariableBCDescriptor>>& remapped_variables_with_bc)
 {
   std::vector<std::shared_ptr<const DiscreteFunctionVariant>> remapped_variables;
@@ -877,20 +876,19 @@ advectByFluxing(const std::shared_ptr<const IMesh> i_new_mesh,
     throw NormalError("remapped quantities are not defined on the same mesh");
   }
 
-  const std::shared_ptr<const IMesh> i_old_mesh = getCommonMesh(remapped_variables);
+  const std::shared_ptr<const MeshVariant> old_mesh_v = getCommonMesh(remapped_variables);
 
-  switch (i_old_mesh->dimension()) {
-  case 1: {
-    return FluxingAdvectionSolver<1>{i_old_mesh, i_new_mesh}.remap(remapped_variables_with_bc);
-  }
-  case 2: {
-    return FluxingAdvectionSolver<2>{i_old_mesh, i_new_mesh}.remap(remapped_variables_with_bc);
-  }
-  case 3: {
-    return FluxingAdvectionSolver<3>{i_old_mesh, i_new_mesh}.remap(remapped_variables_with_bc);
-  }
-  default: {
-    throw UnexpectedError("Invalid mesh dimension");
-  }
-  }
+  return std::visit(
+    [&](auto&& old_mesh, auto&& new_mesh) -> std::vector<std::shared_ptr<const DiscreteFunctionVariant>> {
+      using OldMeshType = typename std::decay_t<decltype(old_mesh)>::element_type;
+      using NewMeshType = typename std::decay_t<decltype(new_mesh)>::element_type;
+
+      if constexpr (std::is_same_v<OldMeshType, NewMeshType>) {
+        constexpr size_t Dimension = OldMeshType::Dimension;
+        return FluxingAdvectionSolver<Dimension>{old_mesh, new_mesh}.remap(remapped_variables_with_bc);
+      } else {
+        throw NormalError("incompatible mesh types");
+      }
+    },
+    old_mesh_v->meshPointer(), new_mesh_v->meshPointer());
 }
diff --git a/src/scheme/FluxingAdvectionSolver.hpp b/src/scheme/FluxingAdvectionSolver.hpp
index 2cbb653cb..5cbb6c76d 100644
--- a/src/scheme/FluxingAdvectionSolver.hpp
+++ b/src/scheme/FluxingAdvectionSolver.hpp
@@ -1,18 +1,19 @@
 #ifndef FLUXING_ADVECION_SOLVER_HPP
 #define FLUXING_ADVECION_SOLVER_HPP
 
-#include <language/utils/FunctionSymbolId.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
 #include <scheme/VariableBCDescriptor.hpp>
 
 #include <vector>
 
+class MeshVariant;
+
 std::vector<std::shared_ptr<const DiscreteFunctionVariant>> advectByFluxing(
-  const std::shared_ptr<const IMesh> new_mesh,
+  const std::shared_ptr<const MeshVariant> new_mesh,
   const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& remapped_variables);
 
 std::vector<std::shared_ptr<const DiscreteFunctionVariant>> advectByFluxing(
-  const std::shared_ptr<const IMesh> new_mesh,
+  const std::shared_ptr<const MeshVariant> new_mesh,
   const std::vector<std::shared_ptr<const VariableBCDescriptor>>& remapped_variables_with_bc);
 
 #endif   // FLUXING_ADVECION_SOLVER_HPP
diff --git a/src/scheme/HyperelasticSolver.cpp b/src/scheme/HyperelasticSolver.cpp
index 2f683fa80..a85ae5b2b 100644
--- a/src/scheme/HyperelasticSolver.cpp
+++ b/src/scheme/HyperelasticSolver.cpp
@@ -6,6 +6,7 @@
 #include <mesh/MeshFaceBoundary.hpp>
 #include <mesh/MeshFlatNodeBoundary.hpp>
 #include <mesh/MeshNodeBoundary.hpp>
+#include <mesh/MeshTraits.hpp>
 #include <mesh/SubItemValuePerItemVariant.hpp>
 #include <scheme/DirichletBoundaryConditionDescriptor.hpp>
 #include <scheme/DiscreteFunctionP0.hpp>
@@ -21,11 +22,11 @@
 #include <variant>
 #include <vector>
 
-template <size_t Dimension>
+template <typename MeshType>
 double
-hyperelastic_dt(const DiscreteFunctionP0<Dimension, const double>& c)
+hyperelastic_dt(const DiscreteFunctionP0<MeshType::Dimension, const double>& c)
 {
-  const Mesh<Connectivity<Dimension>>& mesh = dynamic_cast<const Mesh<Connectivity<Dimension>>&>(*c.mesh());
+  const MeshType& mesh = *c.mesh();
 
   const auto Vj = MeshDataManager::instance().getMeshData(mesh).Vj();
   const auto Sj = MeshDataManager::instance().getMeshData(mesh).sumOverRLjr();
@@ -40,22 +41,18 @@ hyperelastic_dt(const DiscreteFunctionP0<Dimension, const double>& c)
 double
 hyperelastic_dt(const std::shared_ptr<const DiscreteFunctionVariant>& c)
 {
-  std::shared_ptr mesh = getCommonMesh({c});
-
-  switch (mesh->dimension()) {
-  case 1: {
-    return hyperelastic_dt(c->get<DiscreteFunctionP0<1, const double>>());
-  }
-  case 2: {
-    return hyperelastic_dt(c->get<DiscreteFunctionP0<2, const double>>());
-  }
-  case 3: {
-    return hyperelastic_dt(c->get<DiscreteFunctionP0<3, const double>>());
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  std::shared_ptr mesh_v = getCommonMesh({c});
+
+  return std::visit(
+    [&](auto&& mesh) {
+      using MeshType = typename std::decay_t<decltype(mesh)>::element_type;
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        return hyperelastic_dt<MeshType>(c->get<DiscreteFunctionP0<MeshType::Dimension, const double>>());
+      } else {
+        throw NormalError("unexpected mesh type");
+      }
+    },
+    mesh_v->meshPointer());
 }
 
 template <size_t Dimension>
@@ -411,7 +408,7 @@ class HyperelasticSolverHandler::HyperelasticSolver final : public HyperelasticS
       throw NormalError("hyperelastic solver expects P0 functions");
     }
 
-    const MeshType& mesh                = dynamic_cast<const MeshType&>(*i_mesh);
+    const MeshType& mesh                = *i_mesh->get<MeshType>();
     const DiscreteScalarFunction& rho   = rho_v->get<DiscreteScalarFunction>();
     const DiscreteVectorFunction& u     = u_v->get<DiscreteVectorFunction>();
     const DiscreteScalarFunction& aL    = aL_v->get<DiscreteScalarFunction>();
@@ -436,7 +433,7 @@ class HyperelasticSolverHandler::HyperelasticSolver final : public HyperelasticS
                            std::make_shared<const SubItemValuePerItemVariant>(Fjr));
   }
 
-  std::tuple<std::shared_ptr<const IMesh>,
+  std::tuple<std::shared_ptr<const MeshVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
@@ -499,13 +496,14 @@ class HyperelasticSolverHandler::HyperelasticSolver final : public HyperelasticS
     parallel_for(
       mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { new_rho[j] *= Vj[j] / new_Vj[j]; });
 
-    return {new_mesh, std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_rho)),
+    return {std::make_shared<MeshVariant>(new_mesh),
+            std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_rho)),
             std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(new_mesh, new_u)),
             std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_E)),
             std::make_shared<DiscreteFunctionVariant>(DiscreteTensorFunction(new_mesh, new_CG))};
   }
 
-  std::tuple<std::shared_ptr<const IMesh>,
+  std::tuple<std::shared_ptr<const MeshVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
@@ -527,17 +525,17 @@ class HyperelasticSolverHandler::HyperelasticSolver final : public HyperelasticS
       throw NormalError("hyperelastic solver expects P0 functions");
     }
 
-    return this->apply_fluxes(dt,                                       //
-                              dynamic_cast<const MeshType&>(*i_mesh),   //
-                              rho->get<DiscreteScalarFunction>(),       //
-                              u->get<DiscreteVectorFunction>(),         //
-                              E->get<DiscreteScalarFunction>(),         //
-                              CG->get<DiscreteTensorFunction>(),        //
-                              ur->get<NodeValue<const Rd>>(),           //
+    return this->apply_fluxes(dt,                                   //
+                              *i_mesh->get<MeshType>(),             //
+                              rho->get<DiscreteScalarFunction>(),   //
+                              u->get<DiscreteVectorFunction>(),     //
+                              E->get<DiscreteScalarFunction>(),     //
+                              CG->get<DiscreteTensorFunction>(),    //
+                              ur->get<NodeValue<const Rd>>(),       //
                               Fjr->get<NodeValuePerCell<const Rd>>());
   }
 
-  std::tuple<std::shared_ptr<const IMesh>,
+  std::tuple<std::shared_ptr<const MeshVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
@@ -956,27 +954,20 @@ class HyperelasticSolverHandler::HyperelasticSolver<Dimension>::SymmetryBoundary
   ~SymmetryBoundaryCondition() = default;
 };
 
-HyperelasticSolverHandler::HyperelasticSolverHandler(const std::shared_ptr<const IMesh>& i_mesh)
+HyperelasticSolverHandler::HyperelasticSolverHandler(const std::shared_ptr<const MeshVariant>& i_mesh)
 {
   if (not i_mesh) {
     throw NormalError("discrete functions are not defined on the same mesh");
   }
 
-  switch (i_mesh->dimension()) {
-  case 1: {
-    m_hyperelastic_solver = std::make_unique<HyperelasticSolver<1>>();
-    break;
-  }
-  case 2: {
-    m_hyperelastic_solver = std::make_unique<HyperelasticSolver<2>>();
-    break;
-  }
-  case 3: {
-    m_hyperelastic_solver = std::make_unique<HyperelasticSolver<3>>();
-    break;
-  }
-  default: {
-    throw UnexpectedError("invalid mesh dimension");
-  }
-  }
+  std::visit(
+    [&](auto&& mesh) {
+      using MeshType = typename std::decay_t<decltype(mesh)>::element_type;
+      if constexpr (is_polygonal_mesh<MeshType>) {
+        m_hyperelastic_solver = std::make_unique<HyperelasticSolver<MeshType::Dimension>>();
+      } else {
+        throw NormalError("unexpected mesh type");
+      }
+    },
+    i_mesh->meshPointer());
 }
diff --git a/src/scheme/HyperelasticSolver.hpp b/src/scheme/HyperelasticSolver.hpp
index f82cbe361..37a20acbf 100644
--- a/src/scheme/HyperelasticSolver.hpp
+++ b/src/scheme/HyperelasticSolver.hpp
@@ -6,7 +6,7 @@
 #include <vector>
 
 class IBoundaryConditionDescriptor;
-class IMesh;
+class MeshVariant;
 class ItemValueVariant;
 class SubItemValuePerItemVariant;
 class DiscreteFunctionVariant;
@@ -36,7 +36,7 @@ class HyperelasticSolverHandler
       const std::shared_ptr<const DiscreteFunctionVariant>& sigma,
       const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const = 0;
 
-    virtual std::tuple<std::shared_ptr<const IMesh>,
+    virtual std::tuple<std::shared_ptr<const MeshVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>,
@@ -49,7 +49,7 @@ class HyperelasticSolverHandler
                  const std::shared_ptr<const ItemValueVariant>& ur,
                  const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr) const = 0;
 
-    virtual std::tuple<std::shared_ptr<const IMesh>,
+    virtual std::tuple<std::shared_ptr<const MeshVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>,
                        std::shared_ptr<const DiscreteFunctionVariant>,
@@ -65,8 +65,8 @@ class HyperelasticSolverHandler
           const std::shared_ptr<const DiscreteFunctionVariant>& p,
           const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const = 0;
 
-    IHyperelasticSolver()                                 = default;
-    IHyperelasticSolver(IHyperelasticSolver&&)            = default;
+    IHyperelasticSolver()                      = default;
+    IHyperelasticSolver(IHyperelasticSolver&&) = default;
     IHyperelasticSolver& operator=(IHyperelasticSolver&&) = default;
 
     virtual ~IHyperelasticSolver() = default;
@@ -84,7 +84,7 @@ class HyperelasticSolverHandler
     return *m_hyperelastic_solver;
   }
 
-  HyperelasticSolverHandler(const std::shared_ptr<const IMesh>& mesh);
+  HyperelasticSolverHandler(const std::shared_ptr<const MeshVariant>& mesh);
 };
 
 #endif   // HYPERELASTIC_SOLVER_HPP
diff --git a/src/utils/GlobalVariableManager.hpp b/src/utils/GlobalVariableManager.hpp
index 9df677fac..f720252fd 100644
--- a/src/utils/GlobalVariableManager.hpp
+++ b/src/utils/GlobalVariableManager.hpp
@@ -8,6 +8,7 @@ class GlobalVariableManager
 {
  private:
   size_t m_connectivity_id = 0;
+  size_t m_mesh_id         = 0;
 
   static GlobalVariableManager* m_instance;
 
@@ -24,6 +25,13 @@ class GlobalVariableManager
     return m_connectivity_id++;
   }
 
+  PUGS_INLINE
+  size_t
+  getAndIncrementMeshId()
+  {
+    return m_mesh_id++;
+  }
+
   PUGS_INLINE
   static GlobalVariableManager&
   instance()
diff --git a/tests/MeshDataBaseForTests.cpp b/tests/MeshDataBaseForTests.cpp
index ab9d957cf..1f2b485ed 100644
--- a/tests/MeshDataBaseForTests.cpp
+++ b/tests/MeshDataBaseForTests.cpp
@@ -2,6 +2,7 @@
 #include <mesh/CartesianMeshBuilder.hpp>
 #include <mesh/Connectivity.hpp>
 #include <mesh/GmshReader.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <utils/Messenger.hpp>
 #include <utils/PugsAssert.hpp>
 
@@ -12,14 +13,13 @@ const MeshDataBaseForTests* MeshDataBaseForTests::m_instance = nullptr;
 
 MeshDataBaseForTests::MeshDataBaseForTests()
 {
-  m_cartesian_1d_mesh = std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(
-    CartesianMeshBuilder{TinyVector<1>{-1}, TinyVector<1>{3}, TinyVector<1, size_t>{23}}.mesh());
+  m_cartesian_1d_mesh = CartesianMeshBuilder{TinyVector<1>{-1}, TinyVector<1>{3}, TinyVector<1, size_t>{23}}.mesh();
 
-  m_cartesian_2d_mesh = std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(
-    CartesianMeshBuilder{TinyVector<2>{0, -1}, TinyVector<2>{3, 2}, TinyVector<2, size_t>{6, 7}}.mesh());
+  m_cartesian_2d_mesh =
+    CartesianMeshBuilder{TinyVector<2>{0, -1}, TinyVector<2>{3, 2}, TinyVector<2, size_t>{6, 7}}.mesh();
 
-  m_cartesian_3d_mesh = std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(
-    CartesianMeshBuilder{TinyVector<3>{0, 1, 0}, TinyVector<3>{2, -1, 3}, TinyVector<3, size_t>{6, 7, 4}}.mesh());
+  m_cartesian_3d_mesh =
+    CartesianMeshBuilder{TinyVector<3>{0, 1, 0}, TinyVector<3>{2, -1, 3}, TinyVector<3, size_t>{6, 7, 4}}.mesh();
 
   m_unordered_1d_mesh = _buildUnordered1dMesh();
   m_hybrid_2d_mesh    = _buildHybrid2dMesh();
@@ -47,43 +47,43 @@ MeshDataBaseForTests::destroy()
   m_instance = nullptr;
 }
 
-std::shared_ptr<const Mesh<Connectivity<1>>>
+std::shared_ptr<const MeshVariant>
 MeshDataBaseForTests::cartesian1DMesh() const
 {
   return m_cartesian_1d_mesh;
 }
 
-std::shared_ptr<const Mesh<Connectivity<2>>>
+std::shared_ptr<const MeshVariant>
 MeshDataBaseForTests::cartesian2DMesh() const
 {
   return m_cartesian_2d_mesh;
 }
 
-std::shared_ptr<const Mesh<Connectivity<3>>>
+std::shared_ptr<const MeshVariant>
 MeshDataBaseForTests::cartesian3DMesh() const
 {
   return m_cartesian_3d_mesh;
 }
 
-std::shared_ptr<const Mesh<Connectivity<1>>>
+std::shared_ptr<const MeshVariant>
 MeshDataBaseForTests::unordered1DMesh() const
 {
   return m_unordered_1d_mesh;
 }
 
-std::shared_ptr<const Mesh<Connectivity<2>>>
+std::shared_ptr<const MeshVariant>
 MeshDataBaseForTests::hybrid2DMesh() const
 {
   return m_hybrid_2d_mesh;
 }
 
-std::shared_ptr<const Mesh<Connectivity<3>>>
+std::shared_ptr<const MeshVariant>
 MeshDataBaseForTests::hybrid3DMesh() const
 {
   return m_hybrid_3d_mesh;
 }
 
-std::shared_ptr<const Mesh<Connectivity<1>>>
+std::shared_ptr<const MeshVariant>
 MeshDataBaseForTests::_buildUnordered1dMesh()
 {
   const std::string filename = std::filesystem::path{PUGS_BINARY_DIR}.append("tests").append("unordered-1d.msh");
@@ -181,10 +181,10 @@ $EndElements
 )";
   }
 
-  return std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(GmshReader{filename}.mesh());
+  return GmshReader{filename}.mesh();
 }
 
-std::shared_ptr<const Mesh<Connectivity<2>>>
+std::shared_ptr<const MeshVariant>
 MeshDataBaseForTests::_buildHybrid2dMesh()
 {
   const std::string filename = std::filesystem::path{PUGS_BINARY_DIR}.append("tests").append("hybrid-2d.msh");
@@ -358,10 +358,10 @@ $Elements
 $EndElements
 )";
   }
-  return std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(GmshReader{filename}.mesh());
+  return GmshReader{filename}.mesh();
 }
 
-std::shared_ptr<const Mesh<Connectivity<3>>>
+std::shared_ptr<const MeshVariant>
 MeshDataBaseForTests::_buildHybrid3dMesh()
 {
   const std::string filename = std::filesystem::path{PUGS_BINARY_DIR}.append("tests").append("hybrid-3d.msh");
@@ -986,5 +986,5 @@ $Periodic
 $EndPeriodic
 )";
   }
-  return std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(GmshReader{filename}.mesh());
+  return GmshReader{filename}.mesh();
 }
diff --git a/tests/MeshDataBaseForTests.hpp b/tests/MeshDataBaseForTests.hpp
index 79f3379f0..2b092d544 100644
--- a/tests/MeshDataBaseForTests.hpp
+++ b/tests/MeshDataBaseForTests.hpp
@@ -1,32 +1,23 @@
 #ifndef MESH_DATA_BASE_FOR_TESTS_HPP
 #define MESH_DATA_BASE_FOR_TESTS_HPP
 
-#include <mesh/IMesh.hpp>
-
-template <size_t Dimension>
-class Connectivity;
-
-template <typename ConnectivityT>
-class Mesh;
-
 #include <array>
 #include <memory>
 #include <string>
 
+class MeshVariant;
+
 class MeshDataBaseForTests
 {
  public:
-  template <size_t Dimension>
   class NamedMesh
   {
    private:
     const std::string m_name;
-    const std::shared_ptr<const Mesh<Connectivity<Dimension>>> m_mesh;
+    const std::shared_ptr<const MeshVariant> m_mesh_v;
 
    public:
-    NamedMesh(const std::string& name, const std::shared_ptr<const Mesh<Connectivity<Dimension>>>& mesh)
-      : m_name(name), m_mesh(mesh)
-    {}
+    NamedMesh(const std::string& name, const std::shared_ptr<const MeshVariant>& mesh) : m_name(name), m_mesh_v(mesh) {}
 
     const std::string&
     name() const
@@ -37,7 +28,7 @@ class MeshDataBaseForTests
     auto
     mesh() const
     {
-      return m_mesh;
+      return m_mesh_v;
     }
   };
 
@@ -46,27 +37,27 @@ class MeshDataBaseForTests
 
   static const MeshDataBaseForTests* m_instance;
 
-  std::shared_ptr<const Mesh<Connectivity<1>>> m_cartesian_1d_mesh;
-  std::shared_ptr<const Mesh<Connectivity<2>>> m_cartesian_2d_mesh;
-  std::shared_ptr<const Mesh<Connectivity<3>>> m_cartesian_3d_mesh;
+  std::shared_ptr<const MeshVariant> m_cartesian_1d_mesh;
+  std::shared_ptr<const MeshVariant> m_cartesian_2d_mesh;
+  std::shared_ptr<const MeshVariant> m_cartesian_3d_mesh;
 
-  std::shared_ptr<const Mesh<Connectivity<1>>> m_unordered_1d_mesh;
-  std::shared_ptr<const Mesh<Connectivity<2>>> m_hybrid_2d_mesh;
-  std::shared_ptr<const Mesh<Connectivity<3>>> m_hybrid_3d_mesh;
+  std::shared_ptr<const MeshVariant> m_unordered_1d_mesh;
+  std::shared_ptr<const MeshVariant> m_hybrid_2d_mesh;
+  std::shared_ptr<const MeshVariant> m_hybrid_3d_mesh;
 
-  std::shared_ptr<const Mesh<Connectivity<1>>> _buildUnordered1dMesh();
-  std::shared_ptr<const Mesh<Connectivity<2>>> _buildHybrid2dMesh();
-  std::shared_ptr<const Mesh<Connectivity<3>>> _buildHybrid3dMesh();
+  std::shared_ptr<const MeshVariant> _buildUnordered1dMesh();
+  std::shared_ptr<const MeshVariant> _buildHybrid2dMesh();
+  std::shared_ptr<const MeshVariant> _buildHybrid3dMesh();
 
  public:
-  std::shared_ptr<const Mesh<Connectivity<1>>> cartesian1DMesh() const;
-  std::shared_ptr<const Mesh<Connectivity<1>>> unordered1DMesh() const;
+  std::shared_ptr<const MeshVariant> cartesian1DMesh() const;
+  std::shared_ptr<const MeshVariant> unordered1DMesh() const;
 
-  std::shared_ptr<const Mesh<Connectivity<2>>> cartesian2DMesh() const;
-  std::shared_ptr<const Mesh<Connectivity<2>>> hybrid2DMesh() const;
+  std::shared_ptr<const MeshVariant> cartesian2DMesh() const;
+  std::shared_ptr<const MeshVariant> hybrid2DMesh() const;
 
-  std::shared_ptr<const Mesh<Connectivity<3>>> cartesian3DMesh() const;
-  std::shared_ptr<const Mesh<Connectivity<3>>> hybrid3DMesh() const;
+  std::shared_ptr<const MeshVariant> cartesian3DMesh() const;
+  std::shared_ptr<const MeshVariant> hybrid3DMesh() const;
 
   static const MeshDataBaseForTests& get();
 
diff --git a/tests/test_CellIntegrator.cpp b/tests/test_CellIntegrator.cpp
index 9b286a445..cce926b68 100644
--- a/tests/test_CellIntegrator.cpp
+++ b/tests/test_CellIntegrator.cpp
@@ -21,7 +21,7 @@ TEST_CASE("CellIntegrator", "[scheme]")
     {
       using R1 = TinyVector<1>;
 
-      const auto mesh = MeshDataBaseForTests::get().unordered1DMesh();
+      const auto mesh = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
       auto f          = [](const R1& x) -> double { return x[0] * x[0] + 1; };
 
       Array<const double> int_f_per_cell = [=] {
@@ -236,7 +236,7 @@ TEST_CASE("CellIntegrator", "[scheme]")
     {
       using R2 = TinyVector<2>;
 
-      const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+      const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
 
       auto f = [](const R2& X) -> double {
         const double x = X[0];
@@ -495,11 +495,11 @@ TEST_CASE("CellIntegrator", "[scheme]")
 
       std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list;
       mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh));
-      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh)));
+      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh)));
 
       for (const auto& mesh_info : mesh_list) {
         auto mesh_name = mesh_info.first;
-        auto mesh      = mesh_info.second;
+        auto mesh      = mesh_info.second->get<Mesh<Connectivity<3>>>();
 
         SECTION(mesh_name)
         {
@@ -943,7 +943,7 @@ TEST_CASE("CellIntegrator", "[scheme]")
     {
       using R1 = TinyVector<1>;
 
-      const auto mesh = MeshDataBaseForTests::get().unordered1DMesh();
+      const auto mesh = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
       auto f          = [](const R1& x) -> R2 { return R2{x[0] * x[0] + 1, 2 * x[0]}; };
 
       Array<const R2> int_f_per_cell = [=] {
@@ -1156,7 +1156,7 @@ TEST_CASE("CellIntegrator", "[scheme]")
 
     SECTION("2D")
     {
-      const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+      const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
 
       auto f = [](const R2& X) -> R2 {
         const double x = X[0];
@@ -1414,11 +1414,11 @@ TEST_CASE("CellIntegrator", "[scheme]")
 
       std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list;
       mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh));
-      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh)));
+      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh)));
 
       for (const auto& mesh_info : mesh_list) {
         auto mesh_name = mesh_info.first;
-        auto mesh      = mesh_info.second;
+        auto mesh      = mesh_info.second->get<Mesh<Connectivity<3>>>();
 
         SECTION(mesh_name)
         {
@@ -1863,7 +1863,7 @@ TEST_CASE("CellIntegrator", "[scheme]")
     {
       using R1 = TinyVector<1>;
 
-      const auto mesh = MeshDataBaseForTests::get().unordered1DMesh();
+      const auto mesh = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
       auto f          = [](const R1& x) -> R2x2 { return R2x2{x[0] * x[0] + 1, 2 * x[0], 3 - x[0], 3 * x[0] - 1}; };
 
       Array<const R2x2> int_f_per_cell = [=] {
@@ -2081,7 +2081,7 @@ TEST_CASE("CellIntegrator", "[scheme]")
     {
       using R2 = TinyVector<2>;
 
-      const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+      const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
 
       auto f = [](const R2& X) -> R2x2 {
         const double x = X[0];
@@ -2341,11 +2341,11 @@ TEST_CASE("CellIntegrator", "[scheme]")
 
       std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list;
       mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh));
-      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh)));
+      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh)));
 
       for (const auto& mesh_info : mesh_list) {
         auto mesh_name = mesh_info.first;
-        auto mesh      = mesh_info.second;
+        auto mesh      = mesh_info.second->get<Mesh<Connectivity<3>>>();
 
         SECTION(mesh_name)
         {
diff --git a/tests/test_Connectivity.cpp b/tests/test_Connectivity.cpp
index b0465d084..a0277eaf6 100644
--- a/tests/test_Connectivity.cpp
+++ b/tests/test_Connectivity.cpp
@@ -7,6 +7,7 @@
 #include <mesh/ItemValue.hpp>
 #include <mesh/ItemValueUtils.hpp>
 #include <mesh/Mesh.hpp>
+#include <mesh/MeshVariant.hpp>
 #include <utils/Messenger.hpp>
 
 // clazy:excludeall=non-pod-global-static
@@ -19,7 +20,7 @@ TEST_CASE("Connectivity", "[mesh]")
     {
       SECTION("unordered 1D mesh")
       {
-        const auto& mesh = *MeshDataBaseForTests::get().unordered1DMesh();
+        const auto& mesh = *MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
 
         if (parallel::size() == 1) {
           REQUIRE(mesh.numberOfNodes() == 35);
@@ -36,7 +37,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
       SECTION("cartesian 1D mesh")
       {
-        const auto& mesh = *MeshDataBaseForTests::get().cartesian1DMesh();
+        const auto& mesh = *MeshDataBaseForTests::get().cartesian1DMesh()->get<Mesh<Connectivity<1>>>();
 
         if (parallel::size() == 1) {
           REQUIRE(mesh.numberOfNodes() == 24);
@@ -56,7 +57,7 @@ TEST_CASE("Connectivity", "[mesh]")
     {
       SECTION("hybrid 2D mesh")
       {
-        const auto& mesh = *MeshDataBaseForTests::get().hybrid2DMesh();
+        const auto& mesh = *MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
 
         if (parallel::size() == 1) {
           REQUIRE(mesh.numberOfNodes() == 53);
@@ -73,7 +74,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
       SECTION("cartesian 2D mesh")
       {
-        const auto& mesh = *MeshDataBaseForTests::get().cartesian2DMesh();
+        const auto& mesh = *MeshDataBaseForTests::get().cartesian2DMesh()->get<Mesh<Connectivity<2>>>();
 
         if (parallel::size() == 1) {
           REQUIRE(mesh.numberOfNodes() == 56);
@@ -93,7 +94,7 @@ TEST_CASE("Connectivity", "[mesh]")
     {
       SECTION("hybrid 3D mesh")
       {
-        const auto& mesh = *MeshDataBaseForTests::get().hybrid3DMesh();
+        const auto& mesh = *MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
 
         if (parallel::size() == 1) {
           REQUIRE(mesh.numberOfNodes() == 132);
@@ -110,7 +111,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
       SECTION("cartesian 3D mesh")
       {
-        const auto& mesh = *MeshDataBaseForTests::get().cartesian3DMesh();
+        const auto& mesh = *MeshDataBaseForTests::get().cartesian3DMesh()->get<Mesh<Connectivity<3>>>();
 
         if (parallel::size() == 1) {
           REQUIRE(mesh.numberOfNodes() == 280);
@@ -136,7 +137,7 @@ TEST_CASE("Connectivity", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d                        = named_mesh.mesh();
+          auto mesh_1d                        = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
           SECTION("nodes/edges/faces")
@@ -227,7 +228,7 @@ TEST_CASE("Connectivity", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d                        = named_mesh.mesh();
+          auto mesh_2d                        = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
           SECTION("nodes")
@@ -330,7 +331,7 @@ TEST_CASE("Connectivity", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -447,7 +448,7 @@ TEST_CASE("Connectivity", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d                        = named_mesh.mesh();
+          auto mesh_1d                        = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
           auto is_boundary_node = connectivity.isBoundaryNode();
@@ -496,7 +497,7 @@ TEST_CASE("Connectivity", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d                        = named_mesh.mesh();
+          auto mesh_2d                        = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
           SECTION("faces/edges")
@@ -574,7 +575,7 @@ TEST_CASE("Connectivity", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -682,7 +683,7 @@ TEST_CASE("Connectivity", "[mesh]")
         {
           SECTION("cell -> nodes")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
             auto xr   = mesh->xr();
 
             const Connectivity<1>& connectivity = mesh->connectivity();
@@ -701,7 +702,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
           SECTION("node -> cells")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
             const Connectivity<1>& connectivity = mesh->connectivity();
 
@@ -730,7 +731,7 @@ TEST_CASE("Connectivity", "[mesh]")
         {
           SECTION("face -> nodes")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
             const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -750,7 +751,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
           SECTION("node -> faces")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
             const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -769,7 +770,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
           SECTION("node -> cells")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
             const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -788,7 +789,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
           SECTION("face -> cells")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
             const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -817,7 +818,7 @@ TEST_CASE("Connectivity", "[mesh]")
         {
           SECTION("edge -> nodes")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
             const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -837,7 +838,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
           SECTION("face -> nodes")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
             const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -864,7 +865,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
           SECTION("node -> edges")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
             const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -886,7 +887,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
           SECTION("node -> faces")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
             const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -905,7 +906,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
           SECTION("node -> cells")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
             const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -924,7 +925,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
           SECTION("edge -> faces")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
             const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -943,7 +944,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
           SECTION("edge -> cells")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
             const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -962,7 +963,7 @@ TEST_CASE("Connectivity", "[mesh]")
 
           SECTION("face -> cells")
           {
-            auto mesh = named_mesh.mesh();
+            auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
             const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -1019,7 +1020,7 @@ TEST_CASE("Connectivity", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh                           = named_mesh.mesh();
+          auto mesh                           = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
           const Connectivity<1>& connectivity = mesh->connectivity();
 
           SECTION("node <-> cell")
@@ -1091,7 +1092,7 @@ TEST_CASE("Connectivity", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh                           = named_mesh.mesh();
+          auto mesh                           = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
           const Connectivity<2>& connectivity = mesh->connectivity();
 
           SECTION("node <-> cell")
@@ -1193,7 +1194,7 @@ TEST_CASE("Connectivity", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh                           = named_mesh.mesh();
+          auto mesh                           = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
           const Connectivity<3>& connectivity = mesh->connectivity();
 
           SECTION("node <-> cell")
diff --git a/tests/test_DiamondDualConnectivityBuilder.cpp b/tests/test_DiamondDualConnectivityBuilder.cpp
index 45d9cd700..5c9df535a 100644
--- a/tests/test_DiamondDualConnectivityBuilder.cpp
+++ b/tests/test_DiamondDualConnectivityBuilder.cpp
@@ -40,7 +40,7 @@ TEST_CASE("DiamondDualConnectivityBuilder", "[mesh]")
     using ConnectivityType = Connectivity<Dimension>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid2DMesh();
+    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid2DMesh()->get<MeshType>();
     const ConnectivityType& primal_connectivity = mesh->connectivity();
 
     REQUIRE(primal_connectivity.numberOfNodes() == 53);
@@ -150,7 +150,7 @@ TEST_CASE("DiamondDualConnectivityBuilder", "[mesh]")
     using ConnectivityType = Connectivity<Dimension>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid3DMesh();
+    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid3DMesh()->get<MeshType>();
     const ConnectivityType& primal_connectivity = mesh->connectivity();
 
     REQUIRE(primal_connectivity.numberOfNodes() == 132);
diff --git a/tests/test_DiamondDualMeshBuilder.cpp b/tests/test_DiamondDualMeshBuilder.cpp
index 3b9b2564e..debdf09f5 100644
--- a/tests/test_DiamondDualMeshBuilder.cpp
+++ b/tests/test_DiamondDualMeshBuilder.cpp
@@ -21,15 +21,15 @@ TEST_CASE("DiamondDualMeshBuilder", "[mesh]")
     using ConnectivityType = Connectivity<Dimension>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr p_mesh      = MeshDataBaseForTests::get().hybrid2DMesh();
-    const MeshType& primal_mesh = *p_mesh;
+    std::shared_ptr primal_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+    const MeshType& primal_mesh   = *primal_mesh_v->get<Mesh<Connectivity<Dimension>>>();
 
     REQUIRE(primal_mesh.numberOfNodes() == 53);
     REQUIRE(primal_mesh.numberOfFaces() == 110);
     REQUIRE(primal_mesh.numberOfCells() == 58);
 
-    std::shared_ptr p_diamond_dual_mesh = DualMeshManager::instance().getDiamondDualMesh(primal_mesh);
-    const MeshType& dual_mesh           = *p_diamond_dual_mesh;
+    std::shared_ptr diamond_dual_mesh_v = DualMeshManager::instance().getDiamondDualMesh(primal_mesh_v);
+    const MeshType& dual_mesh           = *diamond_dual_mesh_v->get<Mesh<Connectivity<Dimension>>>();
 
     REQUIRE(dual_mesh.numberOfNodes() == 111);
     REQUIRE(dual_mesh.numberOfFaces() == 220);
@@ -88,16 +88,16 @@ TEST_CASE("DiamondDualMeshBuilder", "[mesh]")
     using ConnectivityType = Connectivity<Dimension>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr p_mesh      = MeshDataBaseForTests::get().hybrid3DMesh();
-    const MeshType& primal_mesh = *p_mesh;
+    std::shared_ptr primal_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+    const MeshType& primal_mesh   = *primal_mesh_v->get<Mesh<Connectivity<Dimension>>>();
 
     REQUIRE(primal_mesh.numberOfNodes() == 132);
     REQUIRE(primal_mesh.numberOfEdges() == 452);
     REQUIRE(primal_mesh.numberOfFaces() == 520);
     REQUIRE(primal_mesh.numberOfCells() == 199);
 
-    std::shared_ptr p_diamond_dual_mesh = DualMeshManager::instance().getDiamondDualMesh(primal_mesh);
-    const MeshType& dual_mesh           = *p_diamond_dual_mesh;
+    std::shared_ptr diamond_dual_mesh_v = DualMeshManager::instance().getDiamondDualMesh(primal_mesh_v);
+    const MeshType& dual_mesh           = *diamond_dual_mesh_v->get<Mesh<Connectivity<Dimension>>>();
 
     REQUIRE(dual_mesh.numberOfNodes() == 331);
     REQUIRE(dual_mesh.numberOfEdges() == 1461);
diff --git a/tests/test_DiscreteFunctionIntegrator.cpp b/tests/test_DiscreteFunctionIntegrator.cpp
index 8970a360d..7a42c1f0c 100644
--- a/tests/test_DiscreteFunctionIntegrator.cpp
+++ b/tests/test_DiscreteFunctionIntegrator.cpp
@@ -56,7 +56,7 @@ TEST_CASE("DiscreteFunctionIntegrator", "[scheme]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_1d = named_mesh.mesh();
+        auto mesh_1d_v = named_mesh.mesh();
 
         std::string_view data = R"(
 import math;
@@ -99,9 +99,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_1d);
+            IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_1d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_1d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -116,9 +116,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_1d);
+            IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_1d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_1d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -133,9 +133,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_1d);
+            IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_1d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_1d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -150,9 +150,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_1d);
+            IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_1d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_1d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -170,9 +170,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_1d);
+                                                                   mesh_1d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_1d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -190,9 +190,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_1d);
+                                                                   mesh_1d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_1d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -210,9 +210,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_1d);
+                                                                   mesh_1d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_1d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -230,9 +230,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_1d);
+                                                                   mesh_1d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_1d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -250,9 +250,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_1d);
+                                                                   mesh_1d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_1d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -270,9 +270,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_1d);
+                                                                   mesh_1d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_1d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -292,7 +292,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d_v = named_mesh.mesh();
 
         std::string_view data = R"(
 import math;
@@ -335,9 +335,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_2d);
+            IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_2d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_2d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -352,9 +352,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_2d);
+            IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_2d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_2d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -369,9 +369,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_2d);
+            IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_2d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_2d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -386,9 +386,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_2d);
+            IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_2d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_2d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -406,9 +406,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_2d);
+                                                                   mesh_2d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_2d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -426,9 +426,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_2d);
+                                                                   mesh_2d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_2d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -446,9 +446,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_2d);
+                                                                   mesh_2d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_2d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -466,9 +466,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_2d);
+                                                                   mesh_2d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_2d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -486,9 +486,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_2d);
+                                                                   mesh_2d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_2d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -506,9 +506,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_2d);
+                                                                   mesh_2d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_2d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -528,7 +528,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
 
         std::string_view data = R"(
 import math;
@@ -571,9 +571,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_3d);
+            IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_3d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_3d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -588,9 +588,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_3d);
+            IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_3d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_3d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -605,9 +605,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_3d);
+            IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_3d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_3d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -622,9 +622,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
           CellValue<double> cell_value =
-            IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_3d);
+            IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, mesh_3d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_3d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -642,9 +642,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_3d);
+                                                                   mesh_3d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_3d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -662,9 +662,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_3d);
+                                                                   mesh_3d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_3d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -682,9 +682,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_3d);
+                                                                   mesh_3d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_3d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -702,9 +702,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_3d);
+                                                                   mesh_3d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_3d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -722,9 +722,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_3d);
+                                                                   mesh_3d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_3d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -742,9 +742,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
           CellValue<DataType> cell_value =
             IntegrateCellValue<DataType(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor,
-                                                                   *mesh_3d);
+                                                                   mesh_3d_v);
 
-          DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id);
+          DiscreteFunctionIntegrator integrator(mesh_3d_v, quadrature_descriptor, function_symbol_id);
           DiscreteFunctionVariant discrete_function = integrator.integrate();
 
           REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
diff --git a/tests/test_DiscreteFunctionIntegratorByZone.cpp b/tests/test_DiscreteFunctionIntegratorByZone.cpp
index 4027507e4..c556cf6ca 100644
--- a/tests/test_DiscreteFunctionIntegratorByZone.cpp
+++ b/tests/test_DiscreteFunctionIntegratorByZone.cpp
@@ -53,7 +53,8 @@ TEST_CASE("DiscreteFunctionIntegratorByZone", "[scheme]")
 
     std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor = std::make_shared<GaussQuadratureDescriptor>(3);
 
-    auto mesh_1d = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh_1d_v = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -114,7 +115,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_1d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -141,7 +142,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_1d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -168,7 +169,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_1d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -195,7 +196,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_1d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -224,7 +225,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_1d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -253,7 +254,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_1d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -282,7 +283,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_1d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -311,7 +312,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_1d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -340,7 +341,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_1d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -369,7 +370,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_1d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -382,7 +383,8 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
 
     std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor = std::make_shared<GaussQuadratureDescriptor>(3);
 
-    auto mesh_2d = MeshDataBaseForTests::get().hybrid2DMesh();
+    auto mesh_2d_v = MeshDataBaseForTests::get().hybrid2DMesh();
+    auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -443,7 +445,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_2d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -470,7 +472,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_2d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -497,7 +499,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_2d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -524,7 +526,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_2d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -553,7 +555,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_2d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -582,7 +584,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_2d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -611,7 +613,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_2d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -640,7 +642,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_2d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -669,7 +671,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_2d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -698,7 +700,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_2d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -711,7 +713,8 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
 
     std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor = std::make_shared<GaussQuadratureDescriptor>(3);
 
-    auto mesh_3d = MeshDataBaseForTests::get().hybrid3DMesh();
+    auto mesh_3d_v = MeshDataBaseForTests::get().hybrid3DMesh();
+    auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -772,7 +775,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_3d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -799,7 +802,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_3d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -826,7 +829,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_3d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -853,7 +856,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_3d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>()));
@@ -882,7 +885,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_3d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -911,7 +914,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_3d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -940,7 +943,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_3d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -969,7 +972,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_3d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -998,7 +1001,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_3d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
@@ -1027,7 +1030,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           cell_value[cell_id]  = array[i];
         });
 
-      DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id);
+      DiscreteFunctionIntegrator integrator(mesh_3d_v, zone_list, quadrature_descriptor, function_symbol_id);
       DiscreteFunctionVariant discrete_function = integrator.integrate();
 
       REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>()));
diff --git a/tests/test_DiscreteFunctionInterpoler.cpp b/tests/test_DiscreteFunctionInterpoler.cpp
index ed28e8f92..21bec01b1 100644
--- a/tests/test_DiscreteFunctionInterpoler.cpp
+++ b/tests/test_DiscreteFunctionInterpoler.cpp
@@ -52,7 +52,8 @@ TEST_CASE("DiscreteFunctionInterpoler", "[scheme]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_1d = named_mesh.mesh();
+        auto mesh_1d_v = named_mesh.mesh();
+        auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
         auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj();
 
@@ -103,7 +104,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = std::exp(2 * x[0]) + 3 > 4;
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_1d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -125,7 +126,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = std::floor(3 * x[0] * x[0] + 2);
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_1d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -147,7 +148,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = std::floor(std::exp(2 * x[0]) - 1);
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_1d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -169,7 +170,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = 2 * std::exp(x[0]) + 3;
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_1d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -193,7 +194,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0])};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_1d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -217,7 +218,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]), -3 * x[0]};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_1d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -241,7 +242,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]) + 3, x[0] - 2, 3};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_1d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -265,7 +266,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]) * std::sin(x[0]) + 3};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_1d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -290,7 +291,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
                 DataType{2 * std::exp(x[0]) * std::sin(x[0]) + 3, std::sin(x[0] - 2 * x[0]), 3, x[0] * x[0]};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_1d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -322,7 +323,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
                                              std::exp(x[0])};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_1d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -341,7 +342,8 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d_v = named_mesh.mesh();
+        auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
         auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj();
 
@@ -392,7 +394,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = std::exp(2 * x[0]) < 2 * x[1];
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_2d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -414,7 +416,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = std::floor(3 * (x[0] + x[1]) * (x[0] + x[1]) + 2);
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_2d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -436,7 +438,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = std::floor(std::exp(2 * x[0]) - 3 * x[1]);
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_2d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -458,7 +460,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = 2 * std::exp(x[0]) + 3 * x[1];
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_2d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -482,7 +484,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0])};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_2d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -506,7 +508,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]), -3 * x[1]};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_2d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -530,7 +532,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]) + 3, x[1] - 2, 3};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_2d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -554,7 +556,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_2d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -579,7 +581,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
                 DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, std::sin(x[1] - 2 * x[0]), 3, x[1] * x[0]};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_2d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -612,7 +614,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
                                              std::exp(x[1])};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_2d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -631,7 +633,8 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj();
 
@@ -682,7 +685,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = std::exp(2 * x[0]) < 2 * x[1] + x[2];
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -704,7 +707,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = std::floor(3 * (x[0] + x[1]) * (x[0] + x[1]) + x[2] * x[2]);
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -726,7 +729,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = std::floor(std::exp(2 * x[0]) - 3 * x[1] + x[2]);
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -748,7 +751,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = 2 * std::exp(x[0] + x[2]) + 3 * x[1];
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -772,7 +775,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]) + std::sin(x[1] + x[2])};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -796,7 +799,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]), -3 * x[1] * x[2]};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -820,7 +823,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]) + 3, x[1] - 2, 3 * x[2]};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -844,7 +847,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3 * x[2]};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -869,7 +872,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
                 DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, std::sin(x[2] - 2 * x[0]), 3, x[1] * x[0] - x[2]};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -902,7 +905,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
                                              std::exp(x[1] + x[2])};
             });
 
-          DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(),
+          DiscreteFunctionInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                                 function_symbol_id);
           DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
diff --git a/tests/test_DiscreteFunctionInterpolerByZone.cpp b/tests/test_DiscreteFunctionInterpolerByZone.cpp
index dd242220e..9a95d7ffd 100644
--- a/tests/test_DiscreteFunctionInterpolerByZone.cpp
+++ b/tests/test_DiscreteFunctionInterpolerByZone.cpp
@@ -49,7 +49,8 @@ TEST_CASE("DiscreteFunctionInterpolerByZone", "[scheme]")
   {
     constexpr size_t Dimension = 1;
 
-    auto mesh_1d = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh_1d_v = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -115,7 +116,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_1d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -141,7 +142,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_1d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -167,7 +168,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_1d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -193,7 +194,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_1d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -221,7 +222,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_1d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -249,7 +250,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_1d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -277,7 +278,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_1d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -305,7 +306,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_1d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -334,7 +335,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_1d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -370,7 +371,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_1d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -382,7 +383,8 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
   {
     constexpr size_t Dimension = 2;
 
-    auto mesh_2d = MeshDataBaseForTests::get().hybrid2DMesh();
+    auto mesh_2d_v = MeshDataBaseForTests::get().hybrid2DMesh();
+    auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -448,7 +450,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_2d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -474,7 +476,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_2d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -500,7 +502,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_2d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -526,7 +528,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_2d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -554,7 +556,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_2d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -582,7 +584,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_2d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -610,7 +612,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_2d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -638,7 +640,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_2d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -667,7 +669,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_2d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -704,7 +706,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_2d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -716,7 +718,8 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
   {
     constexpr size_t Dimension = 3;
 
-    auto mesh_3d = MeshDataBaseForTests::get().hybrid3DMesh();
+    auto mesh_3d_v = MeshDataBaseForTests::get().hybrid3DMesh();
+    auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -782,7 +785,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_3d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -808,7 +811,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_3d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -834,7 +837,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_3d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -860,7 +863,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_3d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -888,7 +891,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_3d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -916,7 +919,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_3d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -944,7 +947,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_3d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -972,7 +975,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_3d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -1001,7 +1004,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_3d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -1038,7 +1041,7 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
           }
         });
 
-      DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
+      DiscreteFunctionInterpoler interpoler(mesh_3d_v, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(),
                                             function_symbol_id);
       DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
diff --git a/tests/test_DiscreteFunctionP0.cpp b/tests/test_DiscreteFunctionP0.cpp
index d7d4dff52..ccf962754 100644
--- a/tests/test_DiscreteFunctionP0.cpp
+++ b/tests/test_DiscreteFunctionP0.cpp
@@ -33,7 +33,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
           DiscreteFunctionP0<Dimension, double> f{mesh};
           REQUIRE(f.dataType() == ASTNodeDataType::double_t);
           REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0);
@@ -81,7 +81,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
           DiscreteFunctionP0<Dimension, double> f{mesh};
           REQUIRE(f.dataType() == ASTNodeDataType::double_t);
           REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0);
@@ -129,7 +129,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           DiscreteFunctionP0<Dimension, double> f{mesh};
           REQUIRE(f.dataType() == ASTNodeDataType::double_t);
@@ -191,7 +191,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           DiscreteFunctionP0<Dimension, double> f{mesh};
           f.fill(3);
@@ -220,7 +220,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           DiscreteFunctionP0<Dimension, double> f{mesh};
           f.fill(3);
@@ -249,7 +249,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           DiscreteFunctionP0<Dimension, double> f{mesh};
           f.fill(3);
@@ -291,7 +291,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           SECTION("scalar")
           {
@@ -393,7 +393,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           SECTION("scalar")
           {
@@ -495,7 +495,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           SECTION("scalar")
           {
@@ -599,7 +599,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -684,7 +684,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -1265,7 +1265,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -1851,7 +1851,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -2500,7 +2500,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -2844,7 +2844,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -3188,7 +3188,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -3439,7 +3439,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
               mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
                 const double x = xj[cell_id][0];
                 Ah[cell_id]    = TinyMatrix<2>{x + 1, 2 * x - 3,   //
-                                               -0.2 * x - 1, 2 + x};
+                                            -0.2 * x - 1, 2 + x};
               });
 
             {
@@ -3461,7 +3461,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
               mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
                 const double x = xj[cell_id][0];
                 Ah[cell_id]    = TinyMatrix<2>{x + 1, 2 * x - 3,   //
-                                               -0.2 * x - 1, 2 + x};
+                                            -0.2 * x - 1, 2 + x};
               });
 
             {
@@ -3483,7 +3483,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
               mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
                 const double x = xj[cell_id][0];
                 Ah[cell_id]    = TinyMatrix<2>{x + 1, 2 * x - 3,   //
-                                               -0.2 * x - 1, 2 + x};
+                                            -0.2 * x - 1, 2 + x};
               });
 
             {
@@ -3505,7 +3505,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
               mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
                 const double x = xj[cell_id][0];
                 Ah[cell_id]    = TinyMatrix<2>{x + 1, 2 * x - 3,   //
-                                               -0.2 * x - 1, 2 + x};
+                                            -0.2 * x - 1, 2 + x};
               });
 
             {
@@ -3626,7 +3626,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1 = named_mesh.mesh();
+            auto mesh_1 = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
             std::shared_ptr mesh_2 =
               std::make_shared<Mesh<Connectivity<Dimension>>>(mesh_1->shared_connectivity(), mesh_1->xr());
@@ -3653,7 +3653,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1 = named_mesh.mesh();
+            auto mesh_1 = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
             std::shared_ptr mesh_2 =
               std::make_shared<Mesh<Connectivity<Dimension>>>(mesh_1->shared_connectivity(), mesh_1->xr());
@@ -3680,7 +3680,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]")
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1 = named_mesh.mesh();
+            auto mesh_1 = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
             std::shared_ptr mesh_2 =
               std::make_shared<Mesh<Connectivity<Dimension>>>(mesh_1->shared_connectivity(), mesh_1->xr());
diff --git a/tests/test_DiscreteFunctionP0Vector.cpp b/tests/test_DiscreteFunctionP0Vector.cpp
index 2ab61b240..1bf27ddb2 100644
--- a/tests/test_DiscreteFunctionP0Vector.cpp
+++ b/tests/test_DiscreteFunctionP0Vector.cpp
@@ -34,7 +34,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
           DiscreteFunctionP0Vector<Dimension, double> f{mesh, size};
           REQUIRE(f.dataType() == ASTNodeDataType::double_t);
           REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0Vector);
@@ -82,7 +82,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
           DiscreteFunctionP0Vector<Dimension, double> f{mesh, size};
           REQUIRE(f.dataType() == ASTNodeDataType::double_t);
           REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0Vector);
@@ -130,7 +130,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
           DiscreteFunctionP0Vector<Dimension, double> f{mesh, size};
           REQUIRE(f.dataType() == ASTNodeDataType::double_t);
           REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0Vector);
@@ -192,8 +192,8 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh                  = named_mesh.mesh();
           constexpr size_t Dimension = 1;
+          auto mesh                  = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           DiscreteFunctionP0Vector<Dimension, double> f{mesh, size};
           f.fill(3);
@@ -214,7 +214,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
           DiscreteFunctionP0Vector<Dimension, double> f{mesh, size};
           f.fill(2.3);
 
@@ -234,7 +234,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
           DiscreteFunctionP0Vector<Dimension, double> f{mesh, size};
           f.fill(3.2);
 
@@ -269,7 +269,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           const size_t size       = 3;
           const size_t value      = parallel::rank() + 1;
@@ -315,7 +315,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           const size_t size       = 3;
           const size_t value      = parallel::rank() + 1;
@@ -362,7 +362,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           const size_t size       = 3;
           const size_t value      = parallel::rank() + 1;
@@ -413,7 +413,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -456,7 +456,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -500,7 +500,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -548,7 +548,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -631,7 +631,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -714,7 +714,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -800,7 +800,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -934,7 +934,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
@@ -1072,7 +1072,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh).xj();
 
diff --git a/tests/test_DiscreteFunctionUtils.cpp b/tests/test_DiscreteFunctionUtils.cpp
index 85c916c4c..e7b547f40 100644
--- a/tests/test_DiscreteFunctionUtils.cpp
+++ b/tests/test_DiscreteFunctionUtils.cpp
@@ -21,10 +21,12 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh = named_mesh.mesh();
+        auto mesh_v = named_mesh.mesh();
+        auto mesh   = mesh_v->get<Mesh<Connectivity<Dimension>>>();
 
         std::shared_ptr mesh_copy =
-          std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr());
+          std::make_shared<const std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr());
+        std::shared_ptr mesh_copy_v = std::make_shared<const MeshVariant>(mesh_copy);
 
         SECTION("common mesh")
         {
@@ -39,7 +41,7 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           std::shared_ptr wh_v = std::make_shared<DiscreteFunctionVariant>(wh);
           std::shared_ptr qh_v = std::make_shared<DiscreteFunctionVariant>(qh);
 
-          REQUIRE(getCommonMesh({uh_v, vh_v, wh_v}).get() == mesh.get());
+          REQUIRE(getCommonMesh({uh_v, vh_v, wh_v})->id() == mesh->id());
           REQUIRE(getCommonMesh({uh_v, vh_v, wh_v, qh_v}).use_count() == 0);
         }
 
@@ -72,11 +74,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
         {
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const double>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, double>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -88,11 +90,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyVector<1>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -104,11 +106,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyVector<2>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -120,11 +122,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyVector<3>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -136,11 +138,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyMatrix<1>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -152,11 +154,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyMatrix<2>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -168,11 +170,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyMatrix<3>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -184,11 +186,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DiscreteFunctionT = DiscreteFunctionP0Vector<Dimension, const double>;
           std::shared_ptr uh =
             std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0Vector<Dimension, double>(mesh, 2));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellArrays()[CellId{0}][0]) ==
@@ -207,10 +209,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh = named_mesh.mesh();
-
+        auto mesh_v = named_mesh.mesh();
+        auto mesh   = mesh_v->get<Mesh<Connectivity<Dimension>>>();
         std::shared_ptr mesh_copy =
-          std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr());
+          std::make_shared<const std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr());
+        std::shared_ptr mesh_copy_v = std::make_shared<const MeshVariant>(mesh_copy);
 
         SECTION("common mesh")
         {
@@ -225,7 +228,7 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           std::shared_ptr wh_v = std::make_shared<DiscreteFunctionVariant>(wh);
           std::shared_ptr qh_v = std::make_shared<DiscreteFunctionVariant>(qh);
 
-          REQUIRE(getCommonMesh({uh_v, vh_v, wh_v}).get() == mesh.get());
+          REQUIRE(getCommonMesh({uh_v, vh_v, wh_v})->id() == mesh->id());
           REQUIRE(getCommonMesh({uh_v, vh_v, wh_v, qh_v}).use_count() == 0);
         }
 
@@ -258,11 +261,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
         {
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const double>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, double>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -274,11 +277,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyVector<1>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -290,11 +293,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyVector<2>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -306,11 +309,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyVector<3>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -322,11 +325,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyMatrix<1>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -338,11 +341,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyMatrix<2>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -354,11 +357,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyMatrix<3>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -370,11 +373,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DiscreteFunctionT = DiscreteFunctionP0Vector<Dimension, const double>;
           std::shared_ptr uh =
             std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0Vector<Dimension, double>(mesh, 2));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellArrays()[CellId{0}][0]) ==
@@ -393,10 +396,12 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh = named_mesh.mesh();
+        auto mesh_v = named_mesh.mesh();
+        auto mesh   = mesh_v->get<Mesh<Connectivity<3>>>();
 
         std::shared_ptr mesh_copy =
-          std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr());
+          std::make_shared<const std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr());
+        std::shared_ptr mesh_copy_v = std::make_shared<const MeshVariant>(mesh_copy);
 
         SECTION("common mesh")
         {
@@ -411,7 +416,7 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           std::shared_ptr wh_v = std::make_shared<DiscreteFunctionVariant>(wh);
           std::shared_ptr qh_v = std::make_shared<DiscreteFunctionVariant>(qh);
 
-          REQUIRE(getCommonMesh({uh_v, vh_v, wh_v}).get() == mesh.get());
+          REQUIRE(getCommonMesh({uh_v, vh_v, wh_v})->id() == mesh->id());
           REQUIRE(getCommonMesh({uh_v, vh_v, wh_v, qh_v}).use_count() == 0);
         }
 
@@ -444,11 +449,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
         {
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const double>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, double>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -460,11 +465,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyVector<1>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -476,11 +481,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyVector<2>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -492,11 +497,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyVector<3>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -508,11 +513,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyMatrix<1>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -524,11 +529,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyMatrix<2>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -540,11 +545,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DataType          = TinyMatrix<3>;
           using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>;
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) ==
@@ -556,11 +561,11 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
           using DiscreteFunctionT = DiscreteFunctionP0Vector<Dimension, const double>;
           std::shared_ptr uh =
             std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0Vector<Dimension, double>(mesh, 2));
-          std::shared_ptr vh = shallowCopy(mesh, uh);
+          std::shared_ptr vh = shallowCopy(mesh_v, uh);
 
           REQUIRE(uh == vh);
 
-          std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+          std::shared_ptr wh = shallowCopy(mesh_copy_v, uh);
 
           REQUIRE(uh != wh);
           REQUIRE(&(uh->get<DiscreteFunctionT>().cellArrays()[CellId{0}][0]) ==
@@ -581,14 +586,17 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh = named_mesh.mesh();
+          auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
           std::shared_ptr other_mesh =
-            CartesianMeshBuilder{TinyVector<1>{-1}, TinyVector<1>{3}, TinyVector<1, size_t>{19}}.mesh();
+            CartesianMeshBuilder{TinyVector<1>{-1}, TinyVector<1>{3}, TinyVector<1, size_t>{19}}
+              .mesh()
+              ->get<Mesh<Connectivity<1>>>();
+          std::shared_ptr other_mesh_v = std::make_shared<const MeshVariant>(other_mesh);
 
           std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, double>(mesh));
 
-          REQUIRE_THROWS_WITH(shallowCopy(other_mesh, uh), "error: cannot shallow copy when connectivity changes");
+          REQUIRE_THROWS_WITH(shallowCopy(other_mesh_v, uh), "error: cannot shallow copy when connectivity changes");
         }
       }
     }
@@ -597,12 +605,13 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]")
     {
       constexpr size_t Dimension = 1;
 
-      std::shared_ptr mesh_1d = MeshDataBaseForTests::get().cartesian1DMesh();
-      std::shared_ptr mesh_2d = MeshDataBaseForTests::get().cartesian2DMesh();
+      std::shared_ptr mesh_1d   = MeshDataBaseForTests::get().cartesian1DMesh()->get<Mesh<Connectivity<1>>>();
+      std::shared_ptr mesh_2d_v = std::make_shared<const MeshVariant>(
+        MeshDataBaseForTests::get().cartesian2DMesh()->get<Mesh<Connectivity<2>>>());
 
       std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, double>(mesh_1d));
 
-      REQUIRE_THROWS_WITH(shallowCopy(mesh_2d, uh), "error: incompatible mesh dimensions");
+      REQUIRE_THROWS_WITH(shallowCopy(mesh_2d_v, uh), "error: incompatible mesh dimensions");
     }
   }
 }
diff --git a/tests/test_DiscreteFunctionVectorIntegrator.cpp b/tests/test_DiscreteFunctionVectorIntegrator.cpp
index e57127862..79cd612e5 100644
--- a/tests/test_DiscreteFunctionVectorIntegrator.cpp
+++ b/tests/test_DiscreteFunctionVectorIntegrator.cpp
@@ -67,7 +67,8 @@ TEST_CASE("DiscreteFunctionVectorIntegrator", "[scheme]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_1d = named_mesh.mesh();
+        auto mesh_1d_v = named_mesh.mesh();
+        auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
         std::string_view data = R"(
 import math;
@@ -101,7 +102,7 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3;
         register_function(position, symbol_table, "Z_scalar_non_linear_1d", function_id_list);
         register_function(position, symbol_table, "R_scalar_non_linear_1d", function_id_list);
 
-        DiscreteFunctionVectorIntegrator integrator(mesh_1d, quadrature_descriptor,
+        DiscreteFunctionVectorIntegrator integrator(mesh_1d_v, quadrature_descriptor,
                                                     std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                     function_id_list);
         DiscreteFunctionVariant discrete_function = integrator.integrate();
@@ -156,7 +157,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3;
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d_v = named_mesh.mesh();
+        auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<Dimension>>>();
 
         std::string_view data = R"(
 import math;
@@ -190,7 +192,7 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3;
         register_function(position, symbol_table, "Z_scalar_non_linear_2d", function_id_list);
         register_function(position, symbol_table, "R_scalar_non_linear_2d", function_id_list);
 
-        DiscreteFunctionVectorIntegrator integrator(mesh_2d, quadrature_descriptor,
+        DiscreteFunctionVectorIntegrator integrator(mesh_2d_v, quadrature_descriptor,
                                                     std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                     function_id_list);
         DiscreteFunctionVariant discrete_function = integrator.integrate();
@@ -245,7 +247,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3;
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         std::string_view data = R"(
 import math;
@@ -279,7 +282,7 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2];
         register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list);
         register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list);
 
-        DiscreteFunctionVectorIntegrator integrator(mesh_3d, quadrature_descriptor,
+        DiscreteFunctionVectorIntegrator integrator(mesh_3d_v, quadrature_descriptor,
                                                     std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                     function_id_list);
         DiscreteFunctionVariant discrete_function = integrator.integrate();
@@ -332,7 +335,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2];
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         std::string_view data = R"(
 import math;
@@ -369,7 +373,7 @@ let R2_scalar_non_linear_3d: R^3 -> R^2, x -> [2 * exp(x[0] + x[1]) + 3 * x[2],
           register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list);
           register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list);
 
-          DiscreteFunctionVectorIntegrator integrator(mesh_3d, quadrature_descriptor,
+          DiscreteFunctionVectorIntegrator integrator(mesh_3d_v, quadrature_descriptor,
                                                       std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                       function_id_list);
 
@@ -387,7 +391,7 @@ note: provided function B_scalar_non_linear_2d: R^2 -> B)";
           register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list);
           register_function(position, symbol_table, "R2_scalar_non_linear_3d", function_id_list);
 
-          DiscreteFunctionVectorIntegrator integrator(mesh_3d, quadrature_descriptor,
+          DiscreteFunctionVectorIntegrator integrator(mesh_3d_v, quadrature_descriptor,
                                                       std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                       function_id_list);
 
diff --git a/tests/test_DiscreteFunctionVectorIntegratorByZone.cpp b/tests/test_DiscreteFunctionVectorIntegratorByZone.cpp
index c6526f0c1..f26721770 100644
--- a/tests/test_DiscreteFunctionVectorIntegratorByZone.cpp
+++ b/tests/test_DiscreteFunctionVectorIntegratorByZone.cpp
@@ -64,7 +64,8 @@ TEST_CASE("DiscreteFunctionVectorIntegratorByZone", "[scheme]")
 
     std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor = std::make_shared<GaussQuadratureDescriptor>(3);
 
-    auto mesh_1d = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh_1d_v = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -104,7 +105,7 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3;
     register_function(position, symbol_table, "Z_scalar_non_linear_1d", function_id_list);
     register_function(position, symbol_table, "R_scalar_non_linear_1d", function_id_list);
 
-    DiscreteFunctionVectorIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor,
+    DiscreteFunctionVectorIntegrator integrator(mesh_1d_v, zone_list, quadrature_descriptor,
                                                 std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                 function_id_list);
     DiscreteFunctionVariant discrete_function = integrator.integrate();
@@ -192,7 +193,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3;
 
     std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor = std::make_shared<GaussQuadratureDescriptor>(3);
 
-    auto mesh_2d = MeshDataBaseForTests::get().hybrid2DMesh();
+    auto mesh_2d_v = MeshDataBaseForTests::get().hybrid2DMesh();
+    auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<Dimension>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -232,7 +234,7 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3;
     register_function(position, symbol_table, "Z_scalar_non_linear_2d", function_id_list);
     register_function(position, symbol_table, "R_scalar_non_linear_2d", function_id_list);
 
-    DiscreteFunctionVectorIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor,
+    DiscreteFunctionVectorIntegrator integrator(mesh_2d_v, zone_list, quadrature_descriptor,
                                                 std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                 function_id_list);
     DiscreteFunctionVariant discrete_function = integrator.integrate();
@@ -320,7 +322,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3;
 
     std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor = std::make_shared<GaussQuadratureDescriptor>(3);
 
-    auto mesh_3d = MeshDataBaseForTests::get().hybrid3DMesh();
+    auto mesh_3d_v = MeshDataBaseForTests::get().hybrid3DMesh();
+    auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<Dimension>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -360,7 +363,7 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2];
     register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list);
     register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list);
 
-    DiscreteFunctionVectorIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor,
+    DiscreteFunctionVectorIntegrator integrator(mesh_3d_v, zone_list, quadrature_descriptor,
                                                 std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                 function_id_list);
     DiscreteFunctionVariant discrete_function = integrator.integrate();
diff --git a/tests/test_DiscreteFunctionVectorInterpoler.cpp b/tests/test_DiscreteFunctionVectorInterpoler.cpp
index 2069db16c..0c0d60795 100644
--- a/tests/test_DiscreteFunctionVectorInterpoler.cpp
+++ b/tests/test_DiscreteFunctionVectorInterpoler.cpp
@@ -62,7 +62,8 @@ TEST_CASE("DiscreteFunctionVectorInterpoler", "[scheme]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_1d = named_mesh.mesh();
+        auto mesh_1d_v = named_mesh.mesh();
+        auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
         auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj();
 
@@ -98,7 +99,7 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3;
         register_function(position, symbol_table, "Z_scalar_non_linear_1d", function_id_list);
         register_function(position, symbol_table, "R_scalar_non_linear_1d", function_id_list);
 
-        DiscreteFunctionVectorInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
+        DiscreteFunctionVectorInterpoler interpoler(mesh_1d_v, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                     function_id_list);
         DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -166,7 +167,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3;
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d_v = named_mesh.mesh();
+        auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<Dimension>>>();
 
         auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj();
 
@@ -202,7 +204,7 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3;
         register_function(position, symbol_table, "Z_scalar_non_linear_2d", function_id_list);
         register_function(position, symbol_table, "R_scalar_non_linear_2d", function_id_list);
 
-        DiscreteFunctionVectorInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
+        DiscreteFunctionVectorInterpoler interpoler(mesh_2d_v, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                     function_id_list);
         DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -270,7 +272,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3;
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<Dimension>>>();
 
         auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj();
 
@@ -306,7 +309,7 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2];
         register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list);
         register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list);
 
-        DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
+        DiscreteFunctionVectorInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                     function_id_list);
         DiscreteFunctionVariant discrete_function = interpoler.interpolate();
 
@@ -372,7 +375,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2];
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj();
 
@@ -411,7 +415,7 @@ let R2_scalar_non_linear_3d: R^3 -> R^2, x -> [2 * exp(x[0] + x[1]) + 3 * x[2],
           register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list);
           register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list);
 
-          DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
+          DiscreteFunctionVectorInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                       function_id_list);
 
           const std::string error_msg = R"(error: invalid function type
@@ -428,7 +432,7 @@ note: provided function B_scalar_non_linear_2d: R^2 -> B)";
           register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list);
           register_function(position, symbol_table, "R2_scalar_non_linear_3d", function_id_list);
 
-          DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
+          DiscreteFunctionVectorInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                       function_id_list);
 
           const std::string error_msg = R"(error: vector functions require scalar value type.
@@ -441,7 +445,7 @@ Invalid interpolation value type: R^2)";
         {
           const std::string error_msg = "error: invalid discrete function type for vector interpolation";
 
-          DiscreteFunctionVectorInterpoler interpoler{mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), {}};
+          DiscreteFunctionVectorInterpoler interpoler{mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(), {}};
           REQUIRE_THROWS_WITH(interpoler.interpolate(), error_msg);
         }
       }
diff --git a/tests/test_DiscreteFunctionVectorInterpolerByZone.cpp b/tests/test_DiscreteFunctionVectorInterpolerByZone.cpp
index b486cd528..7468ce997 100644
--- a/tests/test_DiscreteFunctionVectorInterpolerByZone.cpp
+++ b/tests/test_DiscreteFunctionVectorInterpolerByZone.cpp
@@ -59,7 +59,8 @@ TEST_CASE("DiscreteFunctionVectorInterpolerByZone", "[scheme]")
   {
     constexpr size_t Dimension = 1;
 
-    auto mesh_1d = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh_1d_v = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -106,7 +107,7 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3;
     register_function(position, symbol_table, "Z_scalar_non_linear_1d", function_id_list);
     register_function(position, symbol_table, "R_scalar_non_linear_1d", function_id_list);
 
-    DiscreteFunctionVectorInterpoler interpoler(mesh_1d, zone_list,
+    DiscreteFunctionVectorInterpoler interpoler(mesh_1d_v, zone_list,
                                                 std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                 function_id_list);
     DiscreteFunctionVariant discrete_function = interpoler.interpolate();
@@ -184,7 +185,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3;
   {
     constexpr size_t Dimension = 2;
 
-    auto mesh_2d = MeshDataBaseForTests::get().hybrid2DMesh();
+    auto mesh_2d_v = MeshDataBaseForTests::get().hybrid2DMesh();
+    auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<Dimension>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -231,7 +233,7 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3;
     register_function(position, symbol_table, "Z_scalar_non_linear_2d", function_id_list);
     register_function(position, symbol_table, "R_scalar_non_linear_2d", function_id_list);
 
-    DiscreteFunctionVectorInterpoler interpoler(mesh_2d, zone_list,
+    DiscreteFunctionVectorInterpoler interpoler(mesh_2d_v, zone_list,
                                                 std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                 function_id_list);
     DiscreteFunctionVariant discrete_function = interpoler.interpolate();
@@ -309,7 +311,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3;
   {
     constexpr size_t Dimension = 3;
 
-    auto mesh_3d = MeshDataBaseForTests::get().hybrid3DMesh();
+    auto mesh_3d_v = MeshDataBaseForTests::get().hybrid3DMesh();
+    auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<Dimension>>>();
 
     std::vector<std::shared_ptr<const IZoneDescriptor>> zone_list;
     zone_list.push_back(std::make_shared<NamedZoneDescriptor>("LEFT"));
@@ -356,7 +359,7 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2];
     register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list);
     register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list);
 
-    DiscreteFunctionVectorInterpoler interpoler(mesh_3d, zone_list,
+    DiscreteFunctionVectorInterpoler interpoler(mesh_3d_v, zone_list,
                                                 std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                 function_id_list);
     DiscreteFunctionVariant discrete_function = interpoler.interpolate();
@@ -437,7 +440,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2];
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj();
 
@@ -476,7 +480,7 @@ let R2_scalar_non_linear_3d: R^3 -> R^2, x -> [2 * exp(x[0] + x[1]) + 3 * x[2],
           register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list);
           register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list);
 
-          DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
+          DiscreteFunctionVectorInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                       function_id_list);
 
           const std::string error_msg = R"(error: invalid function type
@@ -493,7 +497,7 @@ note: provided function B_scalar_non_linear_2d: R^2 -> B)";
           register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list);
           register_function(position, symbol_table, "R2_scalar_non_linear_3d", function_id_list);
 
-          DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
+          DiscreteFunctionVectorInterpoler interpoler(mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0Vector>(),
                                                       function_id_list);
 
           const std::string error_msg = R"(error: vector functions require scalar value type.
@@ -506,7 +510,7 @@ Invalid interpolation value type: R^2)";
         {
           const std::string error_msg = "error: invalid discrete function type for vector interpolation";
 
-          DiscreteFunctionVectorInterpoler interpoler{mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), {}};
+          DiscreteFunctionVectorInterpoler interpoler{mesh_3d_v, std::make_shared<DiscreteFunctionDescriptorP0>(), {}};
           REQUIRE_THROWS_WITH(interpoler.interpolate(), error_msg);
         }
       }
diff --git a/tests/test_Dual1DConnectivityBuilder.cpp b/tests/test_Dual1DConnectivityBuilder.cpp
index b7a35abfc..b8eb91e42 100644
--- a/tests/test_Dual1DConnectivityBuilder.cpp
+++ b/tests/test_Dual1DConnectivityBuilder.cpp
@@ -39,7 +39,7 @@ TEST_CASE("Dual1DConnectivityBuilder", "[mesh]")
   using ConnectivityType = Connectivity<Dimension>;
   using MeshType         = Mesh<ConnectivityType>;
 
-  std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().unordered1DMesh();
+  std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().unordered1DMesh()->get<MeshType>();
   const ConnectivityType& primal_connectivity = mesh->connectivity();
 
   REQUIRE(primal_connectivity.numberOfNodes() == 35);
diff --git a/tests/test_Dual1DMeshBuilder.cpp b/tests/test_Dual1DMeshBuilder.cpp
index 9471fa881..50b130f12 100644
--- a/tests/test_Dual1DMeshBuilder.cpp
+++ b/tests/test_Dual1DMeshBuilder.cpp
@@ -21,15 +21,15 @@ TEST_CASE("Dual1DMeshBuilder", "[mesh]")
   using ConnectivityType = Connectivity<Dimension>;
   using MeshType         = Mesh<ConnectivityType>;
 
-  std::shared_ptr<const MeshType> p_primal_mesh = MeshDataBaseForTests::get().unordered1DMesh();
+  std::shared_ptr primal_mesh_v = MeshDataBaseForTests::get().unordered1DMesh();
 
-  const MeshType& primal_mesh = *p_primal_mesh;
+  const MeshType& primal_mesh = *primal_mesh_v->get<MeshType>();
 
   REQUIRE(primal_mesh.numberOfNodes() == 35);
   REQUIRE(primal_mesh.numberOfCells() == 34);
 
-  std::shared_ptr p_dual_1d_mesh = DualMeshManager::instance().getDual1DMesh(primal_mesh);
-  const MeshType& dual_mesh      = *p_dual_1d_mesh;
+  std::shared_ptr dual_1d_mesh_v = DualMeshManager::instance().getDual1DMesh(primal_mesh_v);
+  const MeshType& dual_mesh      = *dual_1d_mesh_v->get<MeshType>();
 
   REQUIRE(dual_mesh.numberOfNodes() == 36);
   REQUIRE(dual_mesh.numberOfCells() == 35);
diff --git a/tests/test_DualConnectivityManager.cpp b/tests/test_DualConnectivityManager.cpp
index 00e42e44f..f3b670390 100644
--- a/tests/test_DualConnectivityManager.cpp
+++ b/tests/test_DualConnectivityManager.cpp
@@ -14,7 +14,9 @@ TEST_CASE("DualConnectivityManager", "[mesh]")
   using ConnectivityType = Connectivity<2>;
   using MeshType         = Mesh<ConnectivityType>;
 
-  std::shared_ptr<const MeshType> mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+  std::shared_ptr mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+  std::shared_ptr mesh   = mesh_v->get<MeshType>();
+
   const ConnectivityType& connectivity = mesh->connectivity();
 
   SECTION("diamond dual connectivity access")
diff --git a/tests/test_DualMeshManager.cpp b/tests/test_DualMeshManager.cpp
index 1d05b996a..da9aac557 100644
--- a/tests/test_DualMeshManager.cpp
+++ b/tests/test_DualMeshManager.cpp
@@ -13,18 +13,15 @@ TEST_CASE("DualMeshManager", "[mesh]")
 {
   SECTION("same 1D dual connectivities ")
   {
-    using ConnectivityType = Connectivity<1>;
-    using MeshType         = Mesh<ConnectivityType>;
-
-    std::shared_ptr<const MeshType> mesh = MeshDataBaseForTests::get().unordered1DMesh();
+    std::shared_ptr mesh_v = MeshDataBaseForTests::get().unordered1DMesh();
 
-    std::shared_ptr p_diamond_dual_mesh = DualMeshManager::instance().getDiamondDualMesh(*mesh);
-    std::shared_ptr p_median_dual_mesh  = DualMeshManager::instance().getMedianDualMesh(*mesh);
-    std::shared_ptr p_dual1d_mesh       = DualMeshManager::instance().getDual1DMesh(*mesh);
+    std::shared_ptr diamond_dual_mesh_v = DualMeshManager::instance().getDiamondDualMesh(mesh_v);
+    std::shared_ptr median_dual_mesh_v  = DualMeshManager::instance().getMedianDualMesh(mesh_v);
+    std::shared_ptr dual1d_mesh_v       = DualMeshManager::instance().getDual1DMesh(mesh_v);
 
     // In 1d all these dual meshes are the same
-    REQUIRE(p_dual1d_mesh.get() == p_diamond_dual_mesh.get());
-    REQUIRE(p_dual1d_mesh.get() == p_median_dual_mesh.get());
+    REQUIRE(dual1d_mesh_v->id() == diamond_dual_mesh_v->id());
+    REQUIRE(dual1d_mesh_v->id() == median_dual_mesh_v->id());
   }
 
   SECTION("2D")
@@ -32,16 +29,16 @@ TEST_CASE("DualMeshManager", "[mesh]")
     using ConnectivityType = Connectivity<2>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr<const MeshType> mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+    std::shared_ptr mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
 
     SECTION("diamond dual mesh access")
     {
-      std::shared_ptr p_diamond_dual_mesh = DualMeshManager::instance().getDiamondDualMesh(*mesh);
+      std::shared_ptr p_diamond_dual_mesh = DualMeshManager::instance().getDiamondDualMesh(mesh_v)->get<MeshType>();
 
       const auto ref_counter = p_diamond_dual_mesh.use_count();
 
       {
-        std::shared_ptr p_diamond_dual_mesh2 = DualMeshManager::instance().getDiamondDualMesh(*mesh);
+        std::shared_ptr p_diamond_dual_mesh2 = DualMeshManager::instance().getDiamondDualMesh(mesh_v)->get<MeshType>();
 
         REQUIRE(p_diamond_dual_mesh == p_diamond_dual_mesh2);
         REQUIRE(p_diamond_dual_mesh.use_count() == ref_counter + 1);
@@ -49,18 +46,19 @@ TEST_CASE("DualMeshManager", "[mesh]")
 
       REQUIRE(p_diamond_dual_mesh.use_count() == ref_counter);
 
-      DualMeshManager::instance().deleteMesh(mesh.get());
+      DualMeshManager::instance().deleteMesh(mesh_v->id());
       REQUIRE(p_diamond_dual_mesh.use_count() == ref_counter - 1);
 
       // Can delete mesh from the list again. This means that no
       // dual mesh associated with it is managed.
-      REQUIRE_NOTHROW(DualMeshManager::instance().deleteMesh(mesh.get()));
+      REQUIRE_NOTHROW(DualMeshManager::instance().deleteMesh(mesh_v->id()));
       REQUIRE(p_diamond_dual_mesh.use_count() == ref_counter - 1);
 
       // A new dual mesh is built
-      std::shared_ptr p_diamond_dual_mesh_rebuilt = DualMeshManager::instance().getDiamondDualMesh(*mesh);
+      std::shared_ptr p_diamond_dual_mesh_rebuilt =
+        DualMeshManager::instance().getDiamondDualMesh(mesh_v)->get<MeshType>();
       REQUIRE(p_diamond_dual_mesh != p_diamond_dual_mesh_rebuilt);
-      REQUIRE(p_diamond_dual_mesh.get() != p_diamond_dual_mesh_rebuilt.get());
+      REQUIRE(p_diamond_dual_mesh->id() != p_diamond_dual_mesh_rebuilt->id());
 
       // Exactly two references to the dual mesh. One here and
       // one in the manager.
@@ -69,12 +67,12 @@ TEST_CASE("DualMeshManager", "[mesh]")
 
     SECTION("median dual mesh access")
     {
-      std::shared_ptr p_median_dual_mesh = DualMeshManager::instance().getMedianDualMesh(*mesh);
+      std::shared_ptr p_median_dual_mesh = DualMeshManager::instance().getMedianDualMesh(mesh_v)->get<MeshType>();
 
       const auto ref_counter = p_median_dual_mesh.use_count();
 
       {
-        std::shared_ptr p_median_dual_mesh2 = DualMeshManager::instance().getMedianDualMesh(*mesh);
+        std::shared_ptr p_median_dual_mesh2 = DualMeshManager::instance().getMedianDualMesh(mesh_v)->get<MeshType>();
 
         REQUIRE(p_median_dual_mesh == p_median_dual_mesh2);
         REQUIRE(p_median_dual_mesh.use_count() == ref_counter + 1);
@@ -82,18 +80,19 @@ TEST_CASE("DualMeshManager", "[mesh]")
 
       REQUIRE(p_median_dual_mesh.use_count() == ref_counter);
 
-      DualMeshManager::instance().deleteMesh(mesh.get());
+      DualMeshManager::instance().deleteMesh(mesh_v->id());
       REQUIRE(p_median_dual_mesh.use_count() == ref_counter - 1);
 
       // Can delete mesh from the list again. This means that no
       // dual mesh associated with it is managed.
-      REQUIRE_NOTHROW(DualMeshManager::instance().deleteMesh(mesh.get()));
+      REQUIRE_NOTHROW(DualMeshManager::instance().deleteMesh(mesh_v->id()));
       REQUIRE(p_median_dual_mesh.use_count() == ref_counter - 1);
 
       // A new dual mesh is built
-      std::shared_ptr p_median_dual_mesh_rebuilt = DualMeshManager::instance().getMedianDualMesh(*mesh);
+      std::shared_ptr p_median_dual_mesh_rebuilt =
+        DualMeshManager::instance().getMedianDualMesh(mesh_v)->get<MeshType>();
       REQUIRE(p_median_dual_mesh != p_median_dual_mesh_rebuilt);
-      REQUIRE(p_median_dual_mesh.get() != p_median_dual_mesh_rebuilt.get());
+      REQUIRE(p_median_dual_mesh->id() != p_median_dual_mesh_rebuilt->id());
 
       // Exactly two references to the dual mesh. One here and
       // one in the manager.
@@ -102,15 +101,15 @@ TEST_CASE("DualMeshManager", "[mesh]")
 
     SECTION("check multiple dual mesh using/freeing")
     {
-      std::shared_ptr p_median_dual_mesh  = DualMeshManager::instance().getMedianDualMesh(*mesh);
-      std::shared_ptr p_diamond_dual_mesh = DualMeshManager::instance().getDiamondDualMesh(*mesh);
+      std::shared_ptr p_median_dual_mesh  = DualMeshManager::instance().getMedianDualMesh(mesh_v)->get<MeshType>();
+      std::shared_ptr p_diamond_dual_mesh = DualMeshManager::instance().getDiamondDualMesh(mesh_v)->get<MeshType>();
 
       const auto median_ref_counter  = p_median_dual_mesh.use_count();
       const auto diamond_ref_counter = p_diamond_dual_mesh.use_count();
 
       REQUIRE(p_median_dual_mesh != p_diamond_dual_mesh);
 
-      REQUIRE_NOTHROW(DualMeshManager::instance().deleteMesh(mesh.get()));
+      REQUIRE_NOTHROW(DualMeshManager::instance().deleteMesh(mesh_v->id()));
       REQUIRE(p_median_dual_mesh.use_count() == median_ref_counter - 1);
       REQUIRE(p_diamond_dual_mesh.use_count() == diamond_ref_counter - 1);
     }
@@ -121,16 +120,17 @@ TEST_CASE("DualMeshManager", "[mesh]")
     using ConnectivityType = Connectivity<3>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr<const MeshType> mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+    std::shared_ptr mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+    std::shared_ptr mesh   = mesh_v->get<MeshType>();
 
     SECTION("diamond dual mesh access")
     {
-      std::shared_ptr p_diamond_dual_mesh = DualMeshManager::instance().getDiamondDualMesh(*mesh);
+      std::shared_ptr p_diamond_dual_mesh = DualMeshManager::instance().getDiamondDualMesh(mesh_v)->get<MeshType>();
 
       const auto ref_counter = p_diamond_dual_mesh.use_count();
 
       {
-        std::shared_ptr p_diamond_dual_mesh2 = DualMeshManager::instance().getDiamondDualMesh(*mesh);
+        std::shared_ptr p_diamond_dual_mesh2 = DualMeshManager::instance().getDiamondDualMesh(mesh_v)->get<MeshType>();
 
         REQUIRE(p_diamond_dual_mesh == p_diamond_dual_mesh2);
         REQUIRE(p_diamond_dual_mesh.use_count() == ref_counter + 1);
@@ -138,16 +138,17 @@ TEST_CASE("DualMeshManager", "[mesh]")
 
       REQUIRE(p_diamond_dual_mesh.use_count() == ref_counter);
 
-      DualMeshManager::instance().deleteMesh(mesh.get());
+      DualMeshManager::instance().deleteMesh(mesh->id());
       REQUIRE(p_diamond_dual_mesh.use_count() == ref_counter - 1);
 
       // Can delete mesh from the list again. This means that no
       // dual mesh associated with it is managed.
-      REQUIRE_NOTHROW(DualMeshManager::instance().deleteMesh(mesh.get()));
+      REQUIRE_NOTHROW(DualMeshManager::instance().deleteMesh(mesh->id()));
       REQUIRE(p_diamond_dual_mesh.use_count() == ref_counter - 1);
 
       // A new dual mesh is built
-      std::shared_ptr p_diamond_dual_mesh_rebuilt = DualMeshManager::instance().getDiamondDualMesh(*mesh);
+      std::shared_ptr p_diamond_dual_mesh_rebuilt =
+        DualMeshManager::instance().getDiamondDualMesh(mesh_v)->get<MeshType>();
       REQUIRE(p_diamond_dual_mesh != p_diamond_dual_mesh_rebuilt);
       REQUIRE(p_diamond_dual_mesh.get() != p_diamond_dual_mesh_rebuilt.get());
 
diff --git a/tests/test_EdgeIntegrator.cpp b/tests/test_EdgeIntegrator.cpp
index 46f4d423d..b20cb925f 100644
--- a/tests/test_EdgeIntegrator.cpp
+++ b/tests/test_EdgeIntegrator.cpp
@@ -22,7 +22,7 @@ TEST_CASE("EdgeIntegrator", "[scheme]")
     {
       using R3 = TinyVector<3>;
 
-      auto hybrid_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto hybrid_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
 
       auto f = [](const R3& X) -> double {
         const double x = X[0];
@@ -31,13 +31,14 @@ TEST_CASE("EdgeIntegrator", "[scheme]")
         return x * x + 2 * x * y + 3 * y * y + 2 * z * z - z + 1;
       };
 
-      std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list;
-      mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh));
-      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh)));
+      std::vector<std::pair<std::string, decltype(hybrid_mesh_v)>> mesh_list;
+      mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh_v));
+      mesh_list.push_back(
+        std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh_v)));
 
       for (const auto& mesh_info : mesh_list) {
         auto mesh_name = mesh_info.first;
-        auto mesh      = mesh_info.second;
+        auto mesh      = mesh_info.second->get<Mesh<Connectivity<3>>>();
 
         Array<const double> int_f_per_edge = [=] {
           Array<double> int_f(mesh->numberOfEdges());
@@ -271,7 +272,7 @@ TEST_CASE("EdgeIntegrator", "[scheme]")
     {
       using R3 = TinyVector<3>;
 
-      auto hybrid_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto hybrid_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
 
       auto f = [](const R3& X) -> R2 {
         const double x = X[0];
@@ -280,13 +281,14 @@ TEST_CASE("EdgeIntegrator", "[scheme]")
         return R2{x * x + 2 * x * y + 3 * y * y + 2 * z * z - z + 1, 2 * x + 3 * y - 1};
       };
 
-      std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list;
-      mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh));
-      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh)));
+      std::vector<std::pair<std::string, decltype(hybrid_mesh_v)>> mesh_list;
+      mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh_v));
+      mesh_list.push_back(
+        std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh_v)));
 
       for (const auto& mesh_info : mesh_list) {
         auto mesh_name = mesh_info.first;
-        auto mesh      = mesh_info.second;
+        auto mesh      = mesh_info.second->get<Mesh<Connectivity<3>>>();
 
         Array<const R2> int_f_per_edge = [=] {
           Array<R2> int_f(mesh->numberOfEdges());
@@ -521,7 +523,7 @@ TEST_CASE("EdgeIntegrator", "[scheme]")
     {
       using R3 = TinyVector<3>;
 
-      auto hybrid_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto hybrid_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
 
       auto f = [](const R3& X) -> R2x2 {
         const double x = X[0];
@@ -531,13 +533,14 @@ TEST_CASE("EdgeIntegrator", "[scheme]")
                     3 - 2 * x + 3 * y};
       };
 
-      std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list;
-      mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh));
-      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh)));
+      std::vector<std::pair<std::string, decltype(hybrid_mesh_v)>> mesh_list;
+      mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh_v));
+      mesh_list.push_back(
+        std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh_v)));
 
       for (const auto& mesh_info : mesh_list) {
         auto mesh_name = mesh_info.first;
-        auto mesh      = mesh_info.second;
+        auto mesh      = mesh_info.second->get<Mesh<Connectivity<3>>>();
 
         Array<const R2x2> int_f_per_edge = [=] {
           Array<R2x2> int_f(mesh->numberOfEdges());
diff --git a/tests/test_EmbeddedDiscreteFunctionMathFunctions1D.cpp b/tests/test_EmbeddedDiscreteFunctionMathFunctions1D.cpp
index 887d0785d..aa48d3ffc 100644
--- a/tests/test_EmbeddedDiscreteFunctionMathFunctions1D.cpp
+++ b/tests/test_EmbeddedDiscreteFunctionMathFunctions1D.cpp
@@ -34,7 +34,7 @@ TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions1D", "[scheme]")
   for (const auto& named_mesh : mesh_list) {
     SECTION(named_mesh.name())
     {
-      auto mesh = named_mesh.mesh();
+      auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
       std::shared_ptr other_mesh =
         std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr());
diff --git a/tests/test_EmbeddedDiscreteFunctionMathFunctions2D.cpp b/tests/test_EmbeddedDiscreteFunctionMathFunctions2D.cpp
index ddbf92664..8658aa3da 100644
--- a/tests/test_EmbeddedDiscreteFunctionMathFunctions2D.cpp
+++ b/tests/test_EmbeddedDiscreteFunctionMathFunctions2D.cpp
@@ -36,7 +36,7 @@ TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions2D", "[scheme]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh = named_mesh.mesh();
+        auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
         std::shared_ptr other_mesh =
           std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr());
diff --git a/tests/test_EmbeddedDiscreteFunctionMathFunctions3D.cpp b/tests/test_EmbeddedDiscreteFunctionMathFunctions3D.cpp
index efb77fdde..415173393 100644
--- a/tests/test_EmbeddedDiscreteFunctionMathFunctions3D.cpp
+++ b/tests/test_EmbeddedDiscreteFunctionMathFunctions3D.cpp
@@ -34,7 +34,7 @@ TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions3D", "[scheme]")
   for (const auto& named_mesh : mesh_list) {
     SECTION(named_mesh.name())
     {
-      auto mesh = named_mesh.mesh();
+      auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
       std::shared_ptr other_mesh =
         std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr());
diff --git a/tests/test_EmbeddedDiscreteFunctionOperators1D.cpp b/tests/test_EmbeddedDiscreteFunctionOperators1D.cpp
index 47ff54931..fbbcc8bc1 100644
--- a/tests/test_EmbeddedDiscreteFunctionOperators1D.cpp
+++ b/tests/test_EmbeddedDiscreteFunctionOperators1D.cpp
@@ -25,7 +25,7 @@ TEST_CASE("EmbeddedDiscreteFunctionOperators1D", "[scheme]")
   for (const auto& named_mesh : mesh_list) {
     SECTION(named_mesh.name())
     {
-      auto mesh = named_mesh.mesh();
+      auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
       std::shared_ptr other_mesh =
         std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr());
diff --git a/tests/test_EmbeddedDiscreteFunctionOperators2D.cpp b/tests/test_EmbeddedDiscreteFunctionOperators2D.cpp
index f68856171..d3fece0d8 100644
--- a/tests/test_EmbeddedDiscreteFunctionOperators2D.cpp
+++ b/tests/test_EmbeddedDiscreteFunctionOperators2D.cpp
@@ -25,7 +25,7 @@ TEST_CASE("EmbeddedDiscreteFunctionOperators2D", "[scheme]")
   for (const auto& named_mesh : mesh_list) {
     SECTION(named_mesh.name())
     {
-      auto mesh = named_mesh.mesh();
+      auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
       std::shared_ptr other_mesh =
         std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr());
diff --git a/tests/test_EmbeddedDiscreteFunctionOperators3D.cpp b/tests/test_EmbeddedDiscreteFunctionOperators3D.cpp
index 60b68b473..eb30d18d5 100644
--- a/tests/test_EmbeddedDiscreteFunctionOperators3D.cpp
+++ b/tests/test_EmbeddedDiscreteFunctionOperators3D.cpp
@@ -25,7 +25,7 @@ TEST_CASE("EmbeddedDiscreteFunctionOperators3D", "[scheme]")
   for (const auto& named_mesh : mesh_list) {
     SECTION(named_mesh.name())
     {
-      auto mesh = named_mesh.mesh();
+      auto mesh = named_mesh.mesh()->get<Mesh<Connectivity<Dimension>>>();
 
       std::shared_ptr other_mesh =
         std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr());
diff --git a/tests/test_EmbeddedDiscreteFunctionUtils.cpp b/tests/test_EmbeddedDiscreteFunctionUtils.cpp
index dd2fe97b6..3640ea5b5 100644
--- a/tests/test_EmbeddedDiscreteFunctionUtils.cpp
+++ b/tests/test_EmbeddedDiscreteFunctionUtils.cpp
@@ -34,7 +34,7 @@ TEST_CASE("EmbeddedDiscreteFunctionUtils", "[language]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, double>{mesh_1d}) ==
                   "Vh(P0:R)");
@@ -63,7 +63,7 @@ TEST_CASE("EmbeddedDiscreteFunctionUtils", "[language]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0Vector<1, double>{mesh_1d, 2}) ==
                   "Vh(P0Vector:R)");
diff --git a/tests/test_FaceIntegrator.cpp b/tests/test_FaceIntegrator.cpp
index 916dcf497..092ab55c3 100644
--- a/tests/test_FaceIntegrator.cpp
+++ b/tests/test_FaceIntegrator.cpp
@@ -21,7 +21,8 @@ TEST_CASE("FaceIntegrator", "[scheme]")
     {
       using R2 = TinyVector<2>;
 
-      const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+      const auto mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+      const auto mesh   = mesh_v->get<Mesh<Connectivity<2>>>();
 
       auto f = [](const R2& X) -> double {
         const double x = X[0];
@@ -260,11 +261,11 @@ TEST_CASE("FaceIntegrator", "[scheme]")
 
       std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list;
       mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh));
-      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh)));
+      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh)));
 
       for (const auto& mesh_info : mesh_list) {
         auto mesh_name = mesh_info.first;
-        auto mesh      = mesh_info.second;
+        auto mesh      = mesh_info.second->get<Mesh<Connectivity<3>>>();
 
         Array<const double> int_f_per_face = [=] {
           Array<double> int_f(mesh->numberOfFaces());
@@ -513,7 +514,7 @@ TEST_CASE("FaceIntegrator", "[scheme]")
     {
       using R2 = TinyVector<2>;
 
-      const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+      const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
 
       auto f = [](const R2& X) -> R2 {
         const double x = X[0];
@@ -752,11 +753,11 @@ TEST_CASE("FaceIntegrator", "[scheme]")
 
       std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list;
       mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh));
-      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh)));
+      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh)));
 
       for (const auto& mesh_info : mesh_list) {
         auto mesh_name = mesh_info.first;
-        auto mesh      = mesh_info.second;
+        auto mesh      = mesh_info.second->get<Mesh<Connectivity<3>>>();
 
         Array<const R2> int_f_per_face = [=] {
           Array<R2> int_f(mesh->numberOfFaces());
@@ -1008,7 +1009,7 @@ TEST_CASE("FaceIntegrator", "[scheme]")
     {
       using R2 = TinyVector<2>;
 
-      const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+      const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
 
       auto f = [](const R2& X) -> R2x2 {
         const double x = X[0];
@@ -1247,11 +1248,11 @@ TEST_CASE("FaceIntegrator", "[scheme]")
 
       std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list;
       mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh));
-      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh)));
+      mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh)));
 
       for (const auto& mesh_info : mesh_list) {
         auto mesh_name = mesh_info.first;
-        auto mesh      = mesh_info.second;
+        auto mesh      = mesh_info.second->get<Mesh<Connectivity<3>>>();
 
         Array<const R2x2> int_f_per_face = [=] {
           Array<R2x2> int_f(mesh->numberOfFaces());
diff --git a/tests/test_IntegrateCellArray.cpp b/tests/test_IntegrateCellArray.cpp
index 8a3692ca5..6e45d92a7 100644
--- a/tests/test_IntegrateCellArray.cpp
+++ b/tests/test_IntegrateCellArray.cpp
@@ -54,7 +54,8 @@ TEST_CASE("IntegrateCellArray", "[language]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
           std::string_view data = R"(
 import math;
@@ -140,7 +141,8 @@ let g: R^1 -> R, x -> 2 * exp(x[0]) + 3;
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           std::string_view data = R"(
 import math;
@@ -221,7 +223,7 @@ let g: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3;
       constexpr size_t Dimension = 3;
       auto quadrature_descriptor = GaussLegendreQuadratureDescriptor(3);
 
-      using NamedMesh = MeshDataBaseForTests::NamedMesh<Dimension>;
+      using NamedMesh = MeshDataBaseForTests::NamedMesh;
 
       std::vector<NamedMesh> mesh_list = [] {
         std::vector<NamedMesh> extended_mesh_list;
@@ -230,14 +232,15 @@ let g: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3;
           extended_mesh_list.push_back(MeshDataBaseForTests::get().all3DMeshes()[i]);
         }
         extended_mesh_list.push_back(NamedMesh("diamond dual", DualMeshManager::instance().getDiamondDualMesh(
-                                                                 *MeshDataBaseForTests::get().hybrid3DMesh())));
+                                                                 MeshDataBaseForTests::get().hybrid3DMesh())));
         return extended_mesh_list;
       }();
 
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           std::string_view data = R"(
 import math;
@@ -339,7 +342,9 @@ let g: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3;
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
+
           Array<CellId> cell_list{mesh_1d->numberOfCells() / 2 + mesh_1d->numberOfCells() % 2};
 
           {
@@ -432,7 +437,8 @@ let g: R^1 -> R, x -> 2 * exp(x[0]) + 3;
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           Array<CellId> cell_list{mesh_2d->numberOfCells() / 2 + mesh_2d->numberOfCells() % 2};
 
@@ -522,7 +528,7 @@ let g: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3;
       constexpr size_t Dimension = 3;
       auto quadrature_descriptor = GaussQuadratureDescriptor(3);
 
-      using NamedMesh = MeshDataBaseForTests::NamedMesh<Dimension>;
+      using NamedMesh = MeshDataBaseForTests::NamedMesh;
 
       std::vector<NamedMesh> mesh_list = [] {
         std::vector<NamedMesh> extended_mesh_list;
@@ -531,14 +537,15 @@ let g: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3;
           extended_mesh_list.push_back(MeshDataBaseForTests::get().all3DMeshes()[i]);
         }
         extended_mesh_list.push_back(NamedMesh("diamond dual", DualMeshManager::instance().getDiamondDualMesh(
-                                                                 *MeshDataBaseForTests::get().hybrid3DMesh())));
+                                                                 MeshDataBaseForTests::get().hybrid3DMesh())));
         return extended_mesh_list;
       }();
 
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           Array<CellId> cell_list{mesh_3d->numberOfCells() / 2 + mesh_3d->numberOfCells() % 2};
 
diff --git a/tests/test_IntegrateCellValue.cpp b/tests/test_IntegrateCellValue.cpp
index a230b9530..88d4e356d 100644
--- a/tests/test_IntegrateCellValue.cpp
+++ b/tests/test_IntegrateCellValue.cpp
@@ -52,7 +52,8 @@ TEST_CASE("IntegrateCellValue", "[language]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
           std::string_view data = R"(
 import math;
@@ -109,7 +110,8 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 *
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           std::string_view data = R"(
 import math;
@@ -162,7 +164,7 @@ let R3_2d: R^2 -> R^3, x -> [2*exp(x[0])*sin(x[1])+3, x[0]-2*x[1], 3];
       constexpr size_t Dimension = 3;
       auto quadrature_descriptor = GaussLegendreQuadratureDescriptor(3);
 
-      using NamedMesh = MeshDataBaseForTests::NamedMesh<Dimension>;
+      using NamedMesh = MeshDataBaseForTests::NamedMesh;
 
       std::vector<NamedMesh> mesh_list = [] {
         std::vector<NamedMesh> extended_mesh_list;
@@ -171,14 +173,15 @@ let R3_2d: R^2 -> R^3, x -> [2*exp(x[0])*sin(x[1])+3, x[0]-2*x[1], 3];
           extended_mesh_list.push_back(MeshDataBaseForTests::get().all3DMeshes()[i]);
         }
         extended_mesh_list.push_back(NamedMesh("diamond dual", DualMeshManager::instance().getDiamondDualMesh(
-                                                                 *MeshDataBaseForTests::get().hybrid3DMesh())));
+                                                                 MeshDataBaseForTests::get().hybrid3DMesh())));
         return extended_mesh_list;
       }();
 
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           std::string_view data = R"(
 import math;
@@ -247,7 +250,9 @@ let scalar_3d: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3;
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
+
           Array<CellId> cell_list{mesh_1d->numberOfCells() / 2 + mesh_1d->numberOfCells() % 2};
 
           {
@@ -310,7 +315,8 @@ let scalar_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3;
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           Array<CellId> cell_list{mesh_2d->numberOfCells() / 2 + mesh_2d->numberOfCells() % 2};
 
@@ -373,7 +379,7 @@ let R3_2d: R^2 -> R^3, x -> [2*exp(x[0])*sin(x[1])+3, x[0]-2*x[1], 3];
       constexpr size_t Dimension = 3;
       auto quadrature_descriptor = GaussQuadratureDescriptor(3);
 
-      using NamedMesh = MeshDataBaseForTests::NamedMesh<Dimension>;
+      using NamedMesh = MeshDataBaseForTests::NamedMesh;
 
       std::vector<NamedMesh> mesh_list = [] {
         std::vector<NamedMesh> extended_mesh_list;
@@ -382,14 +388,15 @@ let R3_2d: R^2 -> R^3, x -> [2*exp(x[0])*sin(x[1])+3, x[0]-2*x[1], 3];
           extended_mesh_list.push_back(MeshDataBaseForTests::get().all3DMeshes()[i]);
         }
         extended_mesh_list.push_back(NamedMesh("diamond dual", DualMeshManager::instance().getDiamondDualMesh(
-                                                                 *MeshDataBaseForTests::get().hybrid3DMesh())));
+                                                                 MeshDataBaseForTests::get().hybrid3DMesh())));
         return extended_mesh_list;
       }();
 
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           Array<CellId> cell_list{mesh_3d->numberOfCells() / 2 + mesh_3d->numberOfCells() % 2};
 
diff --git a/tests/test_IntegrateOnCells.cpp b/tests/test_IntegrateOnCells.cpp
index 2104bcbf3..f2f46e73d 100644
--- a/tests/test_IntegrateOnCells.cpp
+++ b/tests/test_IntegrateOnCells.cpp
@@ -54,7 +54,8 @@ TEST_CASE("IntegrateOnCells", "[language]")
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1d = named_mesh.mesh();
+            auto mesh_1d_v = named_mesh.mesh();
+            auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
             std::string_view data = R"(
 import math;
@@ -154,7 +155,8 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 *
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_2d = named_mesh.mesh();
+            auto mesh_2d_v = named_mesh.mesh();
+            auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
             std::string_view data = R"(
 import math;
@@ -251,7 +253,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
       SECTION("3D")
       {
         constexpr size_t Dimension = 3;
-        using NamedMesh            = MeshDataBaseForTests::NamedMesh<Dimension>;
+        using NamedMesh            = MeshDataBaseForTests::NamedMesh;
 
         std::vector<NamedMesh> mesh_list = [] {
           std::vector<NamedMesh> extended_mesh_list;
@@ -260,14 +262,15 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
             extended_mesh_list.push_back(MeshDataBaseForTests::get().all3DMeshes()[i]);
           }
           extended_mesh_list.push_back(NamedMesh("diamond dual", DualMeshManager::instance().getDiamondDualMesh(
-                                                                   *MeshDataBaseForTests::get().hybrid3DMesh())));
+                                                                   MeshDataBaseForTests::get().hybrid3DMesh())));
           return extended_mesh_list;
         }();
 
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_3d = named_mesh.mesh();
+            auto mesh_3d_v = named_mesh.mesh();
+            auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
             std::string_view data = R"(
 import math;
@@ -385,7 +388,9 @@ let R2x2_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1d = named_mesh.mesh();
+            auto mesh_1d_v = named_mesh.mesh();
+            auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
+
             Array<CellId> cell_list{mesh_1d->numberOfCells() / 2 + mesh_1d->numberOfCells() % 2};
 
             {
@@ -494,7 +499,8 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 *
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_2d = named_mesh.mesh();
+            auto mesh_2d_v = named_mesh.mesh();
+            auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
             Array<CellId> cell_list{mesh_2d->numberOfCells() / 2 + mesh_2d->numberOfCells() % 2};
 
@@ -601,7 +607,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
       SECTION("3D")
       {
         constexpr size_t Dimension = 3;
-        using NamedMesh            = MeshDataBaseForTests::NamedMesh<Dimension>;
+        using NamedMesh            = MeshDataBaseForTests::NamedMesh;
 
         std::vector<NamedMesh> mesh_list = [] {
           std::vector<NamedMesh> extended_mesh_list;
@@ -610,14 +616,15 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
             extended_mesh_list.push_back(MeshDataBaseForTests::get().all3DMeshes()[i]);
           }
           extended_mesh_list.push_back(NamedMesh("diamond dual", DualMeshManager::instance().getDiamondDualMesh(
-                                                                   *MeshDataBaseForTests::get().hybrid3DMesh())));
+                                                                   MeshDataBaseForTests::get().hybrid3DMesh())));
           return extended_mesh_list;
         }();
 
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_3d = named_mesh.mesh();
+            auto mesh_3d_v = named_mesh.mesh();
+            auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
             Array<CellId> cell_list{mesh_3d->numberOfCells() / 2 + mesh_3d->numberOfCells() % 2};
 
@@ -750,7 +757,8 @@ let R2x2_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1d = named_mesh.mesh();
+            auto mesh_1d_v = named_mesh.mesh();
+            auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
             std::string_view data = R"(
 import math;
@@ -850,7 +858,8 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 *
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_2d = named_mesh.mesh();
+            auto mesh_2d_v = named_mesh.mesh();
+            auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
             std::string_view data = R"(
 import math;
@@ -947,7 +956,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
       SECTION("3D")
       {
         constexpr size_t Dimension = 3;
-        using NamedMesh            = MeshDataBaseForTests::NamedMesh<Dimension>;
+        using NamedMesh            = MeshDataBaseForTests::NamedMesh;
 
         std::vector<NamedMesh> mesh_list = [] {
           std::vector<NamedMesh> extended_mesh_list;
@@ -956,14 +965,15 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
             extended_mesh_list.push_back(MeshDataBaseForTests::get().all3DMeshes()[i]);
           }
           extended_mesh_list.push_back(NamedMesh("diamond dual", DualMeshManager::instance().getDiamondDualMesh(
-                                                                   *MeshDataBaseForTests::get().hybrid3DMesh())));
+                                                                   MeshDataBaseForTests::get().hybrid3DMesh())));
           return extended_mesh_list;
         }();
 
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_3d = named_mesh.mesh();
+            auto mesh_3d_v = named_mesh.mesh();
+            auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
             std::string_view data = R"(
 import math;
@@ -1081,7 +1091,9 @@ let R2x2_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1d = named_mesh.mesh();
+            auto mesh_1d_v = named_mesh.mesh();
+            auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
+
             Array<CellId> cell_list{mesh_1d->numberOfCells() / 2 + mesh_1d->numberOfCells() % 2};
 
             {
@@ -1190,7 +1202,8 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 *
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_2d = named_mesh.mesh();
+            auto mesh_2d_v = named_mesh.mesh();
+            auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
             Array<CellId> cell_list{mesh_2d->numberOfCells() / 2 + mesh_2d->numberOfCells() % 2};
 
@@ -1297,7 +1310,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
       SECTION("3D")
       {
         constexpr size_t Dimension = 3;
-        using NamedMesh            = MeshDataBaseForTests::NamedMesh<Dimension>;
+        using NamedMesh            = MeshDataBaseForTests::NamedMesh;
 
         std::vector<NamedMesh> mesh_list = [] {
           std::vector<NamedMesh> extended_mesh_list;
@@ -1306,14 +1319,15 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
             extended_mesh_list.push_back(MeshDataBaseForTests::get().all3DMeshes()[i]);
           }
           extended_mesh_list.push_back(NamedMesh("diamond dual", DualMeshManager::instance().getDiamondDualMesh(
-                                                                   *MeshDataBaseForTests::get().hybrid3DMesh())));
+                                                                   MeshDataBaseForTests::get().hybrid3DMesh())));
           return extended_mesh_list;
         }();
 
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_3d = named_mesh.mesh();
+            auto mesh_3d_v = named_mesh.mesh();
+            auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
             Array<CellId> cell_list{mesh_3d->numberOfCells() / 2 + mesh_3d->numberOfCells() % 2};
 
@@ -1446,7 +1460,8 @@ let R2x2_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1d = named_mesh.mesh();
+            auto mesh_1d_v = named_mesh.mesh();
+            auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
             std::string_view data = R"(
 import math;
@@ -1546,7 +1561,8 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 *
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_2d = named_mesh.mesh();
+            auto mesh_2d_v = named_mesh.mesh();
+            auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
             std::string_view data = R"(
 import math;
@@ -1643,7 +1659,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
       SECTION("3D")
       {
         constexpr size_t Dimension = 3;
-        using NamedMesh            = MeshDataBaseForTests::NamedMesh<Dimension>;
+        using NamedMesh            = MeshDataBaseForTests::NamedMesh;
 
         std::vector<NamedMesh> mesh_list = [] {
           std::vector<NamedMesh> extended_mesh_list;
@@ -1652,14 +1668,15 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
             extended_mesh_list.push_back(MeshDataBaseForTests::get().all3DMeshes()[i]);
           }
           extended_mesh_list.push_back(NamedMesh("diamond dual", DualMeshManager::instance().getDiamondDualMesh(
-                                                                   *MeshDataBaseForTests::get().hybrid3DMesh())));
+                                                                   MeshDataBaseForTests::get().hybrid3DMesh())));
           return extended_mesh_list;
         }();
 
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_3d = named_mesh.mesh();
+            auto mesh_3d_v = named_mesh.mesh();
+            auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
             std::string_view data = R"(
 import math;
@@ -1777,7 +1794,9 @@ let R2x2_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1d = named_mesh.mesh();
+            auto mesh_1d_v = named_mesh.mesh();
+            auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
+
             Array<CellId> cell_list{mesh_1d->numberOfCells() / 2 + mesh_1d->numberOfCells() % 2};
 
             {
@@ -1886,7 +1905,8 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 *
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_2d = named_mesh.mesh();
+            auto mesh_2d_v = named_mesh.mesh();
+            auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
             Array<CellId> cell_list{mesh_2d->numberOfCells() / 2 + mesh_2d->numberOfCells() % 2};
 
@@ -1993,7 +2013,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
       SECTION("3D")
       {
         constexpr size_t Dimension = 3;
-        using NamedMesh            = MeshDataBaseForTests::NamedMesh<Dimension>;
+        using NamedMesh            = MeshDataBaseForTests::NamedMesh;
 
         std::vector<NamedMesh> mesh_list = [] {
           std::vector<NamedMesh> extended_mesh_list;
@@ -2002,14 +2022,15 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3
             extended_mesh_list.push_back(MeshDataBaseForTests::get().all3DMeshes()[i]);
           }
           extended_mesh_list.push_back(NamedMesh("diamond dual", DualMeshManager::instance().getDiamondDualMesh(
-                                                                   *MeshDataBaseForTests::get().hybrid3DMesh())));
+                                                                   MeshDataBaseForTests::get().hybrid3DMesh())));
           return extended_mesh_list;
         }();
 
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_3d = named_mesh.mesh();
+            auto mesh_3d_v = named_mesh.mesh();
+            auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
             Array<CellId> cell_list{mesh_3d->numberOfCells() / 2 + mesh_3d->numberOfCells() % 2};
 
diff --git a/tests/test_InterpolateItemArray.cpp b/tests/test_InterpolateItemArray.cpp
index 01720b617..c23dedeaa 100644
--- a/tests/test_InterpolateItemArray.cpp
+++ b/tests/test_InterpolateItemArray.cpp
@@ -56,7 +56,8 @@ TEST_CASE("InterpolateItemArray", "[language]")
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1d = named_mesh.mesh();
+            auto mesh_1d_v = named_mesh.mesh();
+            auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj();
 
@@ -125,7 +126,8 @@ let scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3;
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1d = named_mesh.mesh();
+            auto mesh_1d_v = named_mesh.mesh();
+            auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj();
 
@@ -184,7 +186,8 @@ let f_1d: R^1 -> (R), x -> (2*x[0] + 2, 2 * exp(x[0]) + 3);
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1d = named_mesh.mesh();
+            auto mesh_1d_v = named_mesh.mesh();
+            auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj();
 
@@ -252,7 +255,8 @@ let f_1d: R^1 -> (R^1), x -> (2*x[0] + 2, [2 * exp(x[0]) + 3]);
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_2d = named_mesh.mesh();
+            auto mesh_2d_v = named_mesh.mesh();
+            auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj();
 
@@ -321,7 +325,8 @@ let scalar_non_linear_2d: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3;
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_2d = named_mesh.mesh();
+            auto mesh_2d_v = named_mesh.mesh();
+            auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj();
 
@@ -387,7 +392,8 @@ let f_2d: R^2 -> (R), x -> (2*x[0] + 3*x[1] + 2, 2*exp(x[0])*sin(x[1])+3);
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_3d = named_mesh.mesh();
+            auto mesh_3d_v = named_mesh.mesh();
+            auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj();
 
@@ -456,7 +462,8 @@ let scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3;
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_3d = named_mesh.mesh();
+            auto mesh_3d_v = named_mesh.mesh();
+            auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj();
 
@@ -536,7 +543,8 @@ let f_3d: R^3 -> (R), x -> (2 * x[0] + 3 * x[1] + 2 * x[2] - 1, 2 * exp(x[0]) *
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1d = named_mesh.mesh();
+            auto mesh_1d_v = named_mesh.mesh();
+            auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj();
 
@@ -614,7 +622,8 @@ let scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3;
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_1d = named_mesh.mesh();
+            auto mesh_1d_v = named_mesh.mesh();
+            auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj();
 
@@ -689,7 +698,8 @@ let f_1d: R^1 -> (R), x -> (2*x[0] + 2, 2 * exp(x[0]) + 3);
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_2d = named_mesh.mesh();
+            auto mesh_2d_v = named_mesh.mesh();
+            auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj();
 
@@ -764,7 +774,8 @@ let scalar_non_linear_2d: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3;
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_2d = named_mesh.mesh();
+            auto mesh_2d_v = named_mesh.mesh();
+            auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj();
 
@@ -829,7 +840,8 @@ let f_2d: R^2 -> (R), x -> (2*x[0] + 3*x[1] + 2, 2*exp(x[0])*sin(x[1])+3);
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_2d = named_mesh.mesh();
+            auto mesh_2d_v = named_mesh.mesh();
+            auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj();
 
@@ -906,7 +918,8 @@ let f_2d: R^2 -> (R^2x2), x -> ([[x[0],0],[2-x[1], x[0]*x[1]]], [[2*x[0], x[1]],
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_3d = named_mesh.mesh();
+            auto mesh_3d_v = named_mesh.mesh();
+            auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj();
 
@@ -981,7 +994,8 @@ let scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3;
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_3d = named_mesh.mesh();
+            auto mesh_3d_v = named_mesh.mesh();
+            auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj();
 
@@ -1046,7 +1060,8 @@ let f_3d: R^3 -> (R), x -> (2 * x[0] + 3 * x[1] + 2 * x[2] - 1, 2 * exp(x[0]) *
         for (const auto& named_mesh : mesh_list) {
           SECTION(named_mesh.name())
           {
-            auto mesh_3d = named_mesh.mesh();
+            auto mesh_3d_v = named_mesh.mesh();
+            auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<Dimension>>>();
 
             auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj();
 
diff --git a/tests/test_InterpolateItemValue.cpp b/tests/test_InterpolateItemValue.cpp
index a06eee8ca..8cb3ac498 100644
--- a/tests/test_InterpolateItemValue.cpp
+++ b/tests/test_InterpolateItemValue.cpp
@@ -51,7 +51,8 @@ TEST_CASE("InterpolateItemValue", "[language]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj();
 
@@ -222,7 +223,8 @@ let R2x2_non_linear_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj();
 
@@ -387,7 +389,8 @@ let R2x2_non_linear_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj();
 
@@ -533,7 +536,7 @@ let R2x2_non_linear_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos
               cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) {
                 const TinyVector<Dimension>& x = xj[cell_id];
                 cell_value[cell_id]            = TinyMatrix<2>{2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]),
-                                                               sin(x[0] - 2 * x[1] * x[2]), 3, x[0] * x[1] * x[2]};
+                                                    sin(x[0] - 2 * x[1] * x[2]), 3, x[0] * x[1] * x[2]};
               });
             CellValue<const TinyMatrix<2>> interpolate_value =
               InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj);
@@ -566,7 +569,8 @@ let R2x2_non_linear_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj();
 
@@ -748,7 +752,8 @@ let R2x2_non_linear_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj();
 
@@ -922,7 +927,8 @@ let R2x2_non_linear_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<Dimension>>>();
 
           auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj();
 
diff --git a/tests/test_ItemArray.cpp b/tests/test_ItemArray.cpp
index 644f348c6..313e51972 100644
--- a/tests/test_ItemArray.cpp
+++ b/tests/test_ItemArray.cpp
@@ -33,7 +33,8 @@ TEST_CASE("ItemArray", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_1d = named_mesh.mesh();
+        auto mesh_1d_v = named_mesh.mesh();
+        auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
         const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -71,7 +72,8 @@ TEST_CASE("ItemArray", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d_v = named_mesh.mesh();
+        auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
         const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -107,7 +109,8 @@ TEST_CASE("ItemArray", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -141,7 +144,8 @@ TEST_CASE("ItemArray", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -192,7 +196,8 @@ TEST_CASE("ItemArray", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -227,7 +232,8 @@ TEST_CASE("ItemArray", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d_v = named_mesh.mesh();
+        auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
         const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -273,7 +279,8 @@ TEST_CASE("ItemArray", "[mesh]")
 
   SECTION("output")
   {
-    auto mesh = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh_v = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh   = mesh_v->get<Mesh<Connectivity<1>>>();
 
     Table<int> table{mesh->numberOfCells(), 3};
     for (size_t i = 0; i < table.numberOfRows(); ++i) {
@@ -316,7 +323,8 @@ TEST_CASE("ItemArray", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -346,7 +354,8 @@ TEST_CASE("ItemArray", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -363,7 +372,8 @@ TEST_CASE("ItemArray", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity_2d = mesh_2d->connectivity();
 
@@ -372,7 +382,8 @@ TEST_CASE("ItemArray", "[mesh]")
           for (const auto& named_mesh_3d : mesh_3d_list) {
             SECTION(named_mesh_3d.name())
             {
-              auto mesh_3d = named_mesh_3d.mesh();
+              auto mesh_3d_v = named_mesh_3d.mesh();
+              auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
               const Connectivity<3>& connectivity_3d = mesh_3d->connectivity();
 
diff --git a/tests/test_ItemArrayUtils.cpp b/tests/test_ItemArrayUtils.cpp
index 346345eae..cd0ea471f 100644
--- a/tests/test_ItemArrayUtils.cpp
+++ b/tests/test_ItemArrayUtils.cpp
@@ -25,7 +25,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -299,7 +300,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -573,7 +575,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -850,7 +853,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -879,7 +883,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -908,7 +913,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -940,7 +946,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -969,7 +976,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -998,7 +1006,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -1030,7 +1039,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -1059,7 +1069,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name() + " for double data")
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -1086,7 +1097,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
 
         SECTION(named_mesh.name() + " for N^2 data")
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -1118,7 +1130,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name() + " for size_t data")
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -1140,7 +1153,8 @@ TEST_CASE("ItemArrayUtils", "[mesh]")
 
         SECTION(named_mesh.name() + " for N^3x2 data")
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
diff --git a/tests/test_ItemArrayVariant.cpp b/tests/test_ItemArrayVariant.cpp
index f3b529126..878ee2a7f 100644
--- a/tests/test_ItemArrayVariant.cpp
+++ b/tests/test_ItemArrayVariant.cpp
@@ -11,7 +11,8 @@
 
 TEST_CASE("ItemArrayVariant", "[mesh]")
 {
-  std::shared_ptr mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+  std::shared_ptr mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+  std::shared_ptr mesh   = mesh_v->get<Mesh<Connectivity<2>>>();
 
   const Connectivity<2>& connectivity = *mesh->shared_connectivity();
 
diff --git a/tests/test_ItemArrayVariantFunctionInterpoler.cpp b/tests/test_ItemArrayVariantFunctionInterpoler.cpp
index 05d0ab6a7..50af9207e 100644
--- a/tests/test_ItemArrayVariantFunctionInterpoler.cpp
+++ b/tests/test_ItemArrayVariantFunctionInterpoler.cpp
@@ -55,7 +55,8 @@ TEST_CASE("ItemArrayVariantFunctionInterpoler", "[scheme]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_1d = named_mesh.mesh();
+        auto mesh_1d_v = named_mesh.mesh();
+        auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
         auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj();
         auto xr = mesh_1d->xr();
@@ -129,7 +130,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_array[cell_id][1]         = std::exp(2 * x[0]) + 3 < 4;
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell,
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell,
                                                         {function1_symbol_id, function2_symbol_id});
           std::shared_ptr item_data_variant = interpoler.interpolate();
 
@@ -158,7 +159,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               node_array[node_id][1]         = std::floor(2 * x[0] * x[0]);
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d, ItemType::node,
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::node,
                                                         {function1_symbol_id, function2_symbol_id});
           std::shared_ptr item_data_variant = interpoler.interpolate();
 
@@ -187,7 +188,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_array[cell_id][1]         = std::floor(cos(2 * x[0]) + 0.5);
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell,
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell,
                                                         {function1_symbol_id, function2_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
@@ -224,7 +225,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_array[cell_id][2] = x[0] * std::sin(x[0]);
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell,
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell,
                                                         {function1_symbol_id, function2_symbol_id,
                                                          function3_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
@@ -257,7 +258,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_array[cell_id][1] = DataType{2 * std::exp(x[0]) * x[0]};
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell,
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell,
                                                         {function1_symbol_id, function2_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
@@ -282,7 +283,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_array[cell_id][0] = DataType{2 * std::exp(x[0]), -3 * x[0]};
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, {function_symbol_id});
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, {function_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
           REQUIRE(same_item_array(cell_array, item_array_variant->get<CellArray<DataType>>()));
@@ -305,7 +306,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_array[cell_id][0]         = DataType{2 * std::exp(x[0]) + 3, x[0] - 2, 3};
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, {function_symbol_id});
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, {function_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
           REQUIRE(same_item_array(cell_array, item_array_variant->get<CellArray<DataType>>()));
@@ -328,7 +329,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_array[cell_id][0]         = DataType{2 * std::exp(x[0]) * std::sin(x[0]) + 3};
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, {function_symbol_id});
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, {function_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
           REQUIRE(same_item_array(cell_array, item_array_variant->get<CellArray<DataType>>()));
@@ -352,7 +353,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
                 DataType{2 * std::exp(x[0]) * std::sin(x[0]) + 3, std::sin(x[0] - 2 * x[0]), 3, x[0] * x[0]};
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, {function_symbol_id});
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, {function_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
           REQUIRE(same_item_array(cell_array, item_array_variant->get<CellArray<DataType>>()));
@@ -384,7 +385,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
                                                 std::exp(x[0])};
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, {function_symbol_id});
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, {function_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
           REQUIRE(same_item_array(cell_array, item_array_variant->get<CellArray<DataType>>()));
@@ -410,7 +411,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
 
           FunctionSymbolId function3_symbol_id(std::get<uint64_t>(i_symbol_f3->attributes().value()), symbol_table);
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell,
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell,
                                                         {function1_symbol_id, function2_symbol_id,
                                                          function3_symbol_id});
 
@@ -429,7 +430,8 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d_v = named_mesh.mesh();
+        auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
         auto xl = MeshDataManager::instance().getMeshData(*mesh_2d).xl();
 
@@ -487,7 +489,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               face_array[face_id][1]         = std::sin(2 * x[0]) < x[1];
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_2d, ItemType::face,
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_2d_v, ItemType::face,
                                                         {function1_symbol_id, function2_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
@@ -512,7 +514,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               face_array[face_id][0] = DataType{2 * std::exp(x[0]), -3 * x[1]};
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_2d, ItemType::face, {function_symbol_id});
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_2d_v, ItemType::face, {function_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
           REQUIRE(same_item_array(face_array, item_array_variant->get<FaceArray<DataType>>()));
@@ -544,7 +546,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
                                                 std::exp(x[1])};
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_2d, ItemType::face, {function_symbol_id});
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_2d_v, ItemType::face, {function_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
           REQUIRE(same_item_array(face_array, item_array_variant->get<FaceArray<DataType>>()));
@@ -562,7 +564,8 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         auto xe = MeshDataManager::instance().getMeshData(*mesh_3d).xe();
 
@@ -618,7 +621,7 @@ let R2x2_non_linear_3d: R^3 -> R^2x2,
               edge_array[edge_id][1] = 3 * std::sin(x[0] + x[2]) + 2 * x[1];
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_3d, ItemType::edge,
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_3d_v, ItemType::edge,
                                                         {function1_symbol_id, function2_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
@@ -643,7 +646,7 @@ let R2x2_non_linear_3d: R^3 -> R^2x2,
               edge_array[edge_id][0] = DataType{2 * std::exp(x[0]) + 3, x[1] - 2, 3 * x[2]};
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_3d, ItemType::edge, {function_symbol_id});
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_3d_v, ItemType::edge, {function_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
           REQUIRE(same_item_array(edge_array, item_array_variant->get<EdgeArray<DataType>>()));
@@ -667,7 +670,7 @@ let R2x2_non_linear_3d: R^3 -> R^2x2,
                 DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, std::sin(x[2] - 2 * x[0]), 3, x[1] * x[0] - x[2]};
             });
 
-          ItemArrayVariantFunctionInterpoler interpoler(mesh_3d, ItemType::edge, {function_symbol_id});
+          ItemArrayVariantFunctionInterpoler interpoler(mesh_3d_v, ItemType::edge, {function_symbol_id});
           std::shared_ptr item_array_variant = interpoler.interpolate();
 
           REQUIRE(same_item_array(edge_array, item_array_variant->get<EdgeArray<DataType>>()));
diff --git a/tests/test_ItemValue.cpp b/tests/test_ItemValue.cpp
index e56432747..79b54c22b 100644
--- a/tests/test_ItemValue.cpp
+++ b/tests/test_ItemValue.cpp
@@ -31,7 +31,8 @@ TEST_CASE("ItemValue", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_1d = named_mesh.mesh();
+        auto mesh_1d_v = named_mesh.mesh();
+        auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
         const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -64,7 +65,8 @@ TEST_CASE("ItemValue", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d_v = named_mesh.mesh();
+        auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
         const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -93,7 +95,8 @@ TEST_CASE("ItemValue", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -117,7 +120,8 @@ TEST_CASE("ItemValue", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -147,7 +151,8 @@ TEST_CASE("ItemValue", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -185,7 +190,8 @@ TEST_CASE("ItemValue", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d_v = named_mesh.mesh();
+        auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
         const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -219,7 +225,8 @@ TEST_CASE("ItemValue", "[mesh]")
 
   SECTION("output")
   {
-    auto mesh = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh_v = MeshDataBaseForTests::get().unordered1DMesh();
+    auto mesh   = mesh_v->get<Mesh<Connectivity<1>>>();
 
     Array<int> array{mesh->numberOfCells()};
     for (size_t i = 0; i < array.size(); ++i) {
@@ -260,7 +267,8 @@ TEST_CASE("ItemValue", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -290,7 +298,8 @@ TEST_CASE("ItemValue", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -307,7 +316,8 @@ TEST_CASE("ItemValue", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity_2d = mesh_2d->connectivity();
 
@@ -316,7 +326,8 @@ TEST_CASE("ItemValue", "[mesh]")
           for (const auto& named_mesh_3d : mesh_3d_list) {
             SECTION(named_mesh_3d.name())
             {
-              auto mesh_3d = named_mesh_3d.mesh();
+              auto mesh_3d_v = named_mesh_3d.mesh();
+              auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
               const Connectivity<3>& connectivity_3d = mesh_3d->connectivity();
 
diff --git a/tests/test_ItemValueUtils.cpp b/tests/test_ItemValueUtils.cpp
index e9df51a05..6c5d8b0af 100644
--- a/tests/test_ItemValueUtils.cpp
+++ b/tests/test_ItemValueUtils.cpp
@@ -23,7 +23,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d_v = named_mesh.mesh();
+        auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
         const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -76,7 +77,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -103,7 +105,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -130,7 +133,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -160,7 +164,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -187,7 +192,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -214,7 +220,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -244,7 +251,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name() + " for size_t data")
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -271,7 +279,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
 
         SECTION(named_mesh.name() + " for double data")
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d_v = named_mesh.mesh();
+          auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -307,7 +316,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name() + "for size_t data")
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -334,7 +344,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
 
         SECTION(named_mesh.name() + "for double data")
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -363,7 +374,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
 
         SECTION(named_mesh.name() + "for N^3 data")
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -394,7 +406,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
 
         SECTION(named_mesh.name() + "for R2 data")
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d_v = named_mesh.mesh();
+          auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -438,7 +451,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name() + " for size_t data")
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -460,7 +474,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
 
         SECTION(named_mesh.name() + " for N^3x2 data")
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -486,7 +501,8 @@ TEST_CASE("ItemValueUtils", "[mesh]")
 
         SECTION(named_mesh.name() + "for R^2x3 data")
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d_v = named_mesh.mesh();
+          auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
diff --git a/tests/test_ItemValueVariant.cpp b/tests/test_ItemValueVariant.cpp
index 4d8fca46d..fb4180f4a 100644
--- a/tests/test_ItemValueVariant.cpp
+++ b/tests/test_ItemValueVariant.cpp
@@ -11,9 +11,10 @@
 
 TEST_CASE("ItemValueVariant", "[mesh]")
 {
-  std::shared_ptr mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+  auto mesh_2d_v = MeshDataBaseForTests::get().hybrid2DMesh();
+  auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
-  const Connectivity<2>& connectivity = *mesh->shared_connectivity();
+  const Connectivity<2>& connectivity = *mesh_2d->shared_connectivity();
 
   using R1 = TinyVector<1>;
   using R2 = TinyVector<2>;
diff --git a/tests/test_ItemValueVariantFunctionInterpoler.cpp b/tests/test_ItemValueVariantFunctionInterpoler.cpp
index bd05f94e9..a55435208 100644
--- a/tests/test_ItemValueVariantFunctionInterpoler.cpp
+++ b/tests/test_ItemValueVariantFunctionInterpoler.cpp
@@ -49,7 +49,8 @@ TEST_CASE("ItemValueVariantFunctionInterpoler", "[scheme]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_1d = named_mesh.mesh();
+        auto mesh_1d_v = named_mesh.mesh();
+        auto mesh_1d   = mesh_1d_v->get<Mesh<Connectivity<1>>>();
 
         auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj();
         auto xr = mesh_1d->xr();
@@ -101,7 +102,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = std::exp(2 * x[0]) + 3 > 4;
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, function_symbol_id);
           std::shared_ptr item_data_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(cell_value, item_data_variant->get<CellValue<bool>>()));
@@ -122,7 +123,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               node_value[node_id]            = std::floor(3 * x[0] * x[0] + 2);
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_1d, ItemType::node, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::node, function_symbol_id);
           std::shared_ptr item_data_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(node_value, item_data_variant->get<NodeValue<uint64_t>>()));
@@ -143,7 +144,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = std::floor(std::exp(2 * x[0]) - 1);
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(cell_value, item_value_variant->get<CellValue<int64_t>>()));
@@ -164,7 +165,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = 2 * std::exp(x[0]) + 3;
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(cell_value, item_value_variant->get<CellValue<double>>()));
@@ -187,7 +188,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0])};
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(cell_value, item_value_variant->get<CellValue<DataType>>()));
@@ -210,7 +211,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]), -3 * x[0]};
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(cell_value, item_value_variant->get<CellValue<DataType>>()));
@@ -233,7 +234,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]) + 3, x[0] - 2, 3};
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(cell_value, item_value_variant->get<CellValue<DataType>>()));
@@ -256,7 +257,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
               cell_value[cell_id]            = DataType{2 * std::exp(x[0]) * std::sin(x[0]) + 3};
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(cell_value, item_value_variant->get<CellValue<DataType>>()));
@@ -280,7 +281,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
                 DataType{2 * std::exp(x[0]) * std::sin(x[0]) + 3, std::sin(x[0] - 2 * x[0]), 3, x[0] * x[0]};
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(cell_value, item_value_variant->get<CellValue<DataType>>()));
@@ -311,7 +312,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
                                              std::exp(x[0])};
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_1d, ItemType::cell, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_1d_v, ItemType::cell, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(cell_value, item_value_variant->get<CellValue<DataType>>()));
@@ -329,7 +330,8 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d_v = named_mesh.mesh();
+        auto mesh_2d   = mesh_2d_v->get<Mesh<Connectivity<2>>>();
 
         auto xl = MeshDataManager::instance().getMeshData(*mesh_2d).xl();
 
@@ -375,7 +377,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               face_value[face_id]            = std::exp(2 * x[0]) < 2 * x[1];
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_2d, ItemType::face, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_2d_v, ItemType::face, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(face_value, item_value_variant->get<FaceValue<DataType>>()));
@@ -398,7 +400,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               face_value[face_id]            = DataType{2 * std::exp(x[0]), -3 * x[1]};
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_2d, ItemType::face, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_2d_v, ItemType::face, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(face_value, item_value_variant->get<FaceValue<DataType>>()));
@@ -430,7 +432,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
                                              std::exp(x[1])};
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_2d, ItemType::face, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_2d_v, ItemType::face, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(face_value, item_value_variant->get<FaceValue<DataType>>()));
@@ -448,7 +450,8 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d_v = named_mesh.mesh();
+        auto mesh_3d   = mesh_3d_v->get<Mesh<Connectivity<3>>>();
 
         auto xe = MeshDataManager::instance().getMeshData(*mesh_3d).xe();
 
@@ -492,7 +495,7 @@ let R2x2_non_linear_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               edge_value[edge_id]            = 2 * std::exp(x[0] + x[2]) + 3 * x[1];
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_3d, ItemType::edge, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_3d_v, ItemType::edge, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(edge_value, item_value_variant->get<EdgeValue<double>>()));
@@ -515,7 +518,7 @@ let R2x2_non_linear_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
               edge_value[edge_id]            = DataType{2 * std::exp(x[0]) + 3, x[1] - 2, 3 * x[2]};
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_3d, ItemType::edge, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_3d_v, ItemType::edge, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(edge_value, item_value_variant->get<EdgeValue<DataType>>()));
@@ -539,7 +542,7 @@ let R2x2_non_linear_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin(
                 DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, std::sin(x[2] - 2 * x[0]), 3, x[1] * x[0] - x[2]};
             });
 
-          ItemValueVariantFunctionInterpoler interpoler(mesh_3d, ItemType::edge, function_symbol_id);
+          ItemValueVariantFunctionInterpoler interpoler(mesh_3d_v, ItemType::edge, function_symbol_id);
           std::shared_ptr item_value_variant = interpoler.interpolate();
 
           REQUIRE(same_item_value(edge_value, item_value_variant->get<EdgeValue<DataType>>()));
diff --git a/tests/test_MedianDualConnectivityBuilder.cpp b/tests/test_MedianDualConnectivityBuilder.cpp
index 6d091bd03..34728918d 100644
--- a/tests/test_MedianDualConnectivityBuilder.cpp
+++ b/tests/test_MedianDualConnectivityBuilder.cpp
@@ -40,7 +40,7 @@ TEST_CASE("MedianDualConnectivityBuilder", "[mesh]")
     using ConnectivityType = Connectivity<Dimension>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid2DMesh();
+    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid2DMesh()->get<MeshType>();
     const ConnectivityType& primal_connectivity = mesh->connectivity();
 
     REQUIRE(primal_connectivity.numberOfNodes() == 53);
diff --git a/tests/test_MedianDualMeshBuilder.cpp b/tests/test_MedianDualMeshBuilder.cpp
index 062c48264..ac2fe9bb4 100644
--- a/tests/test_MedianDualMeshBuilder.cpp
+++ b/tests/test_MedianDualMeshBuilder.cpp
@@ -21,15 +21,15 @@ TEST_CASE("MedianDualMeshBuilder", "[mesh]")
     using ConnectivityType = Connectivity<Dimension>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr p_mesh      = MeshDataBaseForTests::get().hybrid2DMesh();
-    const MeshType& primal_mesh = *p_mesh;
+    std::shared_ptr primal_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+    const MeshType& primal_mesh   = *primal_mesh_v->get<MeshType>();
 
     REQUIRE(primal_mesh.numberOfNodes() == 53);
     REQUIRE(primal_mesh.numberOfFaces() == 110);
     REQUIRE(primal_mesh.numberOfCells() == 58);
 
-    std::shared_ptr p_diamond_dual_mesh = DualMeshManager::instance().getMedianDualMesh(primal_mesh);
-    const MeshType& dual_mesh           = *p_diamond_dual_mesh;
+    std::shared_ptr p_diamond_dual_mesh = DualMeshManager::instance().getMedianDualMesh(primal_mesh_v);
+    const MeshType& dual_mesh           = *p_diamond_dual_mesh->get<MeshType>();
 
     REQUIRE(dual_mesh.numberOfNodes() == 192);
     REQUIRE(dual_mesh.numberOfFaces() == 244);
diff --git a/tests/test_MeshEdgeBoundary.cpp b/tests/test_MeshEdgeBoundary.cpp
index 74facdecf..0659a644b 100644
--- a/tests/test_MeshEdgeBoundary.cpp
+++ b/tests/test_MeshEdgeBoundary.cpp
@@ -53,7 +53,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]")
     SECTION("cartesian 1d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian1DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -86,7 +86,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]")
     SECTION("unordered 1d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -126,7 +126,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]")
     SECTION("cartesian 2d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -158,7 +158,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]")
     SECTION("hybrid 2d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -198,7 +198,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]")
     SECTION("cartesian 3d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -230,7 +230,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]")
     SECTION("hybrid 3d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -270,7 +270,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]")
       using MeshType         = Mesh<ConnectivityType>;
 
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       NamedBoundaryDescriptor named_boundary_descriptor("invalid_boundary");
 
@@ -288,7 +288,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE");
 
@@ -305,7 +305,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE");
 
@@ -322,7 +322,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE1");
 
diff --git a/tests/test_MeshEdgeInterface.cpp b/tests/test_MeshEdgeInterface.cpp
index a42258e45..b42324c5a 100644
--- a/tests/test_MeshEdgeInterface.cpp
+++ b/tests/test_MeshEdgeInterface.cpp
@@ -53,7 +53,7 @@ TEST_CASE("MeshEdgeInterface", "[mesh]")
     SECTION("unordered 1d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -93,7 +93,7 @@ TEST_CASE("MeshEdgeInterface", "[mesh]")
     SECTION("hybrid 2d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -133,7 +133,7 @@ TEST_CASE("MeshEdgeInterface", "[mesh]")
     SECTION("hybrid 3d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -173,7 +173,7 @@ TEST_CASE("MeshEdgeInterface", "[mesh]")
       using MeshType         = Mesh<ConnectivityType>;
 
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       NamedInterfaceDescriptor named_interface_descriptor("invalid_interface");
 
diff --git a/tests/test_MeshFaceBoundary.cpp b/tests/test_MeshFaceBoundary.cpp
index aa4142d6b..9345506d7 100644
--- a/tests/test_MeshFaceBoundary.cpp
+++ b/tests/test_MeshFaceBoundary.cpp
@@ -53,7 +53,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]")
     SECTION("cartesian 1d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian1DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -86,7 +86,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]")
     SECTION("unordered 1d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -126,7 +126,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]")
     SECTION("cartesian 2d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -158,7 +158,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]")
     SECTION("hybrid 2d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -198,7 +198,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]")
     SECTION("cartesian 3d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -230,7 +230,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]")
     SECTION("hybrid 3d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -270,7 +270,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]")
       using MeshType         = Mesh<ConnectivityType>;
 
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       NamedBoundaryDescriptor named_boundary_descriptor("invalid_boundary");
 
@@ -288,7 +288,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE");
 
@@ -305,7 +305,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE");
 
@@ -322,7 +322,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE1");
 
diff --git a/tests/test_MeshFaceInterface.cpp b/tests/test_MeshFaceInterface.cpp
index 503ae0a1f..d762b712c 100644
--- a/tests/test_MeshFaceInterface.cpp
+++ b/tests/test_MeshFaceInterface.cpp
@@ -53,7 +53,7 @@ TEST_CASE("MeshFaceInterface", "[mesh]")
     SECTION("unordered 1d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -93,7 +93,7 @@ TEST_CASE("MeshFaceInterface", "[mesh]")
     SECTION("hybrid 2d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -133,7 +133,7 @@ TEST_CASE("MeshFaceInterface", "[mesh]")
     SECTION("hybrid 3d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -173,7 +173,7 @@ TEST_CASE("MeshFaceInterface", "[mesh]")
       using MeshType         = Mesh<ConnectivityType>;
 
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       NamedInterfaceDescriptor named_interface_descriptor("invalid_interface");
 
@@ -191,7 +191,7 @@ TEST_CASE("MeshFaceInterface", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedInterfaceDescriptor named_interface_descriptor("XMIN");
 
@@ -208,7 +208,7 @@ TEST_CASE("MeshFaceInterface", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedInterfaceDescriptor named_interface_descriptor("XMIN");
 
@@ -225,7 +225,7 @@ TEST_CASE("MeshFaceInterface", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedInterfaceDescriptor named_interface_descriptor("XMIN");
 
diff --git a/tests/test_MeshFlatEdgeBoundary.cpp b/tests/test_MeshFlatEdgeBoundary.cpp
index 16d843ade..18070e5db 100644
--- a/tests/test_MeshFlatEdgeBoundary.cpp
+++ b/tests/test_MeshFlatEdgeBoundary.cpp
@@ -58,7 +58,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
       SECTION("cartesian 1d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian1DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -121,7 +121,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
       SECTION("unordered 1d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -194,7 +194,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
       SECTION("cartesian 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -290,7 +290,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
       SECTION("hybrid 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -397,7 +397,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
       SECTION("cartesian 3d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -572,7 +572,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
       SECTION("hybrid 3d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -763,7 +763,8 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
 
       SECTION("cartesian 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -845,7 +846,8 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -943,7 +945,8 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
 
       SECTION("cartesian 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1038,7 +1041,8 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
 
       SECTION("hybrid 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1148,7 +1152,8 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1246,7 +1251,8 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
 
       SECTION("cartesian 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1358,7 +1364,8 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]")
 
       SECTION("hybrid 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
diff --git a/tests/test_MeshFlatFaceBoundary.cpp b/tests/test_MeshFlatFaceBoundary.cpp
index 08e1779ce..f7a3ea2fa 100644
--- a/tests/test_MeshFlatFaceBoundary.cpp
+++ b/tests/test_MeshFlatFaceBoundary.cpp
@@ -58,7 +58,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
       SECTION("cartesian 1d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian1DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -121,7 +121,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
       SECTION("unordered 1d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -194,7 +194,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
       SECTION("cartesian 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -268,7 +268,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
       SECTION("hybrid 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -353,7 +353,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
       SECTION("cartesian 3d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -440,7 +440,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
       SECTION("hybrid 3d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -543,7 +543,8 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
 
       SECTION("cartesian 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -625,7 +626,8 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -723,7 +725,8 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
 
       SECTION("cartesian 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -818,7 +821,8 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
 
       SECTION("hybrid 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -928,7 +932,8 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1026,7 +1031,8 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
 
       SECTION("cartesian 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1138,7 +1144,8 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]")
 
       SECTION("hybrid 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
diff --git a/tests/test_MeshFlatNodeBoundary.cpp b/tests/test_MeshFlatNodeBoundary.cpp
index 760f55642..bb5cbff8a 100644
--- a/tests/test_MeshFlatNodeBoundary.cpp
+++ b/tests/test_MeshFlatNodeBoundary.cpp
@@ -58,7 +58,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
       SECTION("cartesian 1d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian1DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -121,7 +121,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
       SECTION("unordered 1d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -194,7 +194,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
       SECTION("cartesian 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -290,7 +290,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
       SECTION("hybrid 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -397,7 +397,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
       SECTION("cartesian 3d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -572,7 +572,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
       SECTION("hybrid 3d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -763,7 +763,8 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
 
       SECTION("cartesian 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -845,7 +846,8 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -943,7 +945,8 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
 
       SECTION("cartesian 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1038,7 +1041,8 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
 
       SECTION("hybrid 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1148,7 +1152,8 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
 
       SECTION("cartesian 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1243,7 +1248,8 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
 
       SECTION("cartesian 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1353,7 +1359,8 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1451,7 +1458,8 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
 
       SECTION("cartesian 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1563,7 +1571,8 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]")
 
       SECTION("hybrid 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
diff --git a/tests/test_MeshLineEdgeBoundary.cpp b/tests/test_MeshLineEdgeBoundary.cpp
index 31d9a578b..7eb85182b 100644
--- a/tests/test_MeshLineEdgeBoundary.cpp
+++ b/tests/test_MeshLineEdgeBoundary.cpp
@@ -58,7 +58,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]")
       SECTION("cartesian 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -154,7 +154,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]")
       SECTION("hybrid 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -261,7 +261,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]")
       SECTION("cartesian 3d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -403,7 +403,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]")
       SECTION("hybrid 3d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -563,7 +563,8 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]")
 
       SECTION("cartesian 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -645,7 +646,8 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -743,7 +745,8 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]")
 
       SECTION("cartesian 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -831,7 +834,8 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]")
 
       SECTION("hybrid 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -934,7 +938,8 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1032,7 +1037,8 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]")
 
       SECTION("cartesian 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1143,7 +1149,8 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]")
 
       SECTION("hybrid 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
diff --git a/tests/test_MeshLineFaceBoundary.cpp b/tests/test_MeshLineFaceBoundary.cpp
index 86150aa40..dc0a1b8f8 100644
--- a/tests/test_MeshLineFaceBoundary.cpp
+++ b/tests/test_MeshLineFaceBoundary.cpp
@@ -58,7 +58,7 @@ TEST_CASE("MeshLineFaceBoundary", "[mesh]")
       SECTION("cartesian 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -154,7 +154,7 @@ TEST_CASE("MeshLineFaceBoundary", "[mesh]")
       SECTION("hybrid 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -267,7 +267,8 @@ TEST_CASE("MeshLineFaceBoundary", "[mesh]")
 
       SECTION("cartesian 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -349,7 +350,8 @@ TEST_CASE("MeshLineFaceBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -446,7 +448,8 @@ TEST_CASE("MeshLineFaceBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
diff --git a/tests/test_MeshLineNodeBoundary.cpp b/tests/test_MeshLineNodeBoundary.cpp
index f82f69b14..cccc65686 100644
--- a/tests/test_MeshLineNodeBoundary.cpp
+++ b/tests/test_MeshLineNodeBoundary.cpp
@@ -58,7 +58,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]")
       SECTION("cartesian 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -154,7 +154,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]")
       SECTION("hybrid 2d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -261,7 +261,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]")
       SECTION("cartesian 3d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -403,7 +403,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]")
       SECTION("hybrid 3d")
       {
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -563,7 +563,8 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]")
 
       SECTION("cartesian 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -645,7 +646,8 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -743,7 +745,8 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]")
 
       SECTION("cartesian 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -831,7 +834,8 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]")
 
       SECTION("hybrid 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -934,7 +938,8 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]")
 
       SECTION("hybrid 2d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1032,7 +1037,8 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]")
 
       SECTION("cartesian 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().cartesian3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
@@ -1143,7 +1149,8 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]")
 
       SECTION("hybrid 3d")
       {
-        std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
+        std::shared_ptr p_mesh   = p_mesh_v->get<MeshType>();
 
         const ConnectivityType& connectivity = p_mesh->connectivity();
 
diff --git a/tests/test_MeshNodeBoundary.cpp b/tests/test_MeshNodeBoundary.cpp
index aab1cfd50..b91de432f 100644
--- a/tests/test_MeshNodeBoundary.cpp
+++ b/tests/test_MeshNodeBoundary.cpp
@@ -53,7 +53,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]")
     SECTION("cartesian 1d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian1DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -86,7 +86,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]")
     SECTION("unordered 1d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -126,7 +126,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]")
     SECTION("cartesian 2d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -159,7 +159,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]")
     SECTION("hybrid 2d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -200,7 +200,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]")
     SECTION("cartesian 3d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -240,7 +240,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]")
     SECTION("hybrid 3d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -288,7 +288,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]")
       using MeshType         = Mesh<ConnectivityType>;
 
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       NamedBoundaryDescriptor named_boundary_descriptor("invalid_boundary");
 
@@ -306,7 +306,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE");
 
@@ -323,7 +323,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE");
 
@@ -340,7 +340,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE1");
 
diff --git a/tests/test_MeshNodeInterface.cpp b/tests/test_MeshNodeInterface.cpp
index d74080e3f..88884df79 100644
--- a/tests/test_MeshNodeInterface.cpp
+++ b/tests/test_MeshNodeInterface.cpp
@@ -53,7 +53,7 @@ TEST_CASE("MeshNodeInterface", "[mesh]")
     SECTION("unordered 1d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -93,7 +93,7 @@ TEST_CASE("MeshNodeInterface", "[mesh]")
     SECTION("hybrid 2d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -133,7 +133,7 @@ TEST_CASE("MeshNodeInterface", "[mesh]")
     SECTION("hybrid 3d")
     {
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       const ConnectivityType& connectivity = mesh.connectivity();
 
@@ -173,7 +173,7 @@ TEST_CASE("MeshNodeInterface", "[mesh]")
       using MeshType         = Mesh<ConnectivityType>;
 
       std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-      const MeshType& mesh   = *p_mesh;
+      const MeshType& mesh   = *p_mesh->get<MeshType>();
 
       NamedInterfaceDescriptor named_interface_descriptor("invalid_interface");
 
@@ -191,7 +191,7 @@ TEST_CASE("MeshNodeInterface", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedInterfaceDescriptor named_interface_descriptor("XMIN");
 
@@ -208,7 +208,7 @@ TEST_CASE("MeshNodeInterface", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedInterfaceDescriptor named_interface_descriptor("XMIN");
 
@@ -225,7 +225,7 @@ TEST_CASE("MeshNodeInterface", "[mesh]")
         using MeshType         = Mesh<ConnectivityType>;
 
         std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
-        const MeshType& mesh   = *p_mesh;
+        const MeshType& mesh   = *p_mesh->get<MeshType>();
 
         NamedInterfaceDescriptor named_interface_descriptor("ZMAX");
 
diff --git a/tests/test_ParallelChecker_read.cpp b/tests/test_ParallelChecker_read.cpp
index 233d37e34..02fb226b6 100644
--- a/tests/test_ParallelChecker_read.cpp
+++ b/tests/test_ParallelChecker_read.cpp
@@ -199,7 +199,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
   {
     // ItemValues
     {   // 1d
-      auto mesh                           = MeshDataBaseForTests::get().unordered1DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<1>& connectivity = mesh->connectivity();
 
@@ -363,7 +363,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
       }
 
       {
-        auto other_mesh                           = MeshDataBaseForTests::get().cartesian1DMesh();
+        auto other_mesh = MeshDataBaseForTests::get().cartesian1DMesh()->get<Mesh<Connectivity<1>>>();
         const Connectivity<1>& other_connectivity = other_mesh->connectivity();
 
         CellValue<double> other_shape{other_connectivity};
@@ -377,7 +377,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
 
     // ItemArray
     {   // 1d
-      auto mesh                           = MeshDataBaseForTests::get().unordered1DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<1>& connectivity = mesh->connectivity();
 
@@ -503,7 +503,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
       }
 
       {
-        auto other_mesh                           = MeshDataBaseForTests::get().cartesian1DMesh();
+        auto other_mesh = MeshDataBaseForTests::get().cartesian1DMesh()->get<Mesh<Connectivity<1>>>();
         const Connectivity<1>& other_connectivity = other_mesh->connectivity();
 
         CellArray<double> other_shape{other_connectivity, 2};
@@ -517,7 +517,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
 
     // ItemValues
     {   // 2d
-      auto mesh                           = MeshDataBaseForTests::get().hybrid2DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -610,7 +610,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
 
     // ItemArray
     {   // 2d
-      auto mesh                           = MeshDataBaseForTests::get().hybrid2DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -747,7 +747,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
       }
 
       {
-        auto other_mesh                           = MeshDataBaseForTests::get().cartesian2DMesh();
+        auto other_mesh = MeshDataBaseForTests::get().cartesian2DMesh()->get<Mesh<Connectivity<2>>>();
         const Connectivity<2>& other_connectivity = other_mesh->connectivity();
 
         FaceArray<DataType> other_shape{other_connectivity, 2};
@@ -761,7 +761,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
 
     // ItemValues
     {   // 3d
-      auto mesh                           = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -858,7 +858,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
 
     // ItemArray
     {   // 3d
-      auto mesh                           = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -991,7 +991,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
       }
 
       {
-        auto other_mesh                           = MeshDataBaseForTests::get().cartesian2DMesh();
+        auto other_mesh = MeshDataBaseForTests::get().cartesian2DMesh()->get<Mesh<Connectivity<2>>>();
         const Connectivity<2>& other_connectivity = other_mesh->connectivity();
 
         FaceArray<DataType> other_shape{other_connectivity, 2};
@@ -1007,7 +1007,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
   {
     // SubItemValuePerItem
     {   // 1d
-      auto mesh                           = MeshDataBaseForTests::get().unordered1DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<1>& connectivity = mesh->connectivity();
 
@@ -1198,7 +1198,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
       }
 
       {
-        auto other_mesh                           = MeshDataBaseForTests::get().cartesian1DMesh();
+        auto other_mesh = MeshDataBaseForTests::get().cartesian1DMesh()->get<Mesh<Connectivity<1>>>();
         const Connectivity<1>& other_connectivity = other_mesh->connectivity();
 
         CellValuePerNode<double> other_shape{other_connectivity};
@@ -1212,7 +1212,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
 
     // SubItemArrayPerItem
     {   // 1d
-      auto mesh                           = MeshDataBaseForTests::get().unordered1DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<1>& connectivity = mesh->connectivity();
 
@@ -1352,7 +1352,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
       }
 
       {
-        auto other_mesh                           = MeshDataBaseForTests::get().cartesian1DMesh();
+        auto other_mesh = MeshDataBaseForTests::get().cartesian1DMesh()->get<Mesh<Connectivity<1>>>();
         const Connectivity<1>& other_connectivity = other_mesh->connectivity();
 
         CellArray<double> other_shape{other_connectivity, 2};
@@ -1366,7 +1366,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
 
     // SubItemValuePerItem
     {   // 2d
-      auto mesh                           = MeshDataBaseForTests::get().hybrid2DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -1503,7 +1503,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
       }
 
       {
-        auto other_mesh                           = MeshDataBaseForTests::get().cartesian2DMesh();
+        auto other_mesh = MeshDataBaseForTests::get().cartesian2DMesh()->get<Mesh<Connectivity<2>>>();
         const Connectivity<2>& other_connectivity = other_mesh->connectivity();
 
         FaceArray<DataType> other_shape{other_connectivity, 2};
@@ -1517,7 +1517,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
 
     // SubItemArrayPerItem
     {   // 2d
-      auto mesh                           = MeshDataBaseForTests::get().hybrid2DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -1708,7 +1708,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
       }
 
       {
-        auto other_mesh                           = MeshDataBaseForTests::get().cartesian2DMesh();
+        auto other_mesh = MeshDataBaseForTests::get().cartesian2DMesh()->get<Mesh<Connectivity<2>>>();
         const Connectivity<2>& other_connectivity = other_mesh->connectivity();
 
         CellValuePerNode<double> other_shape{other_connectivity};
@@ -1722,7 +1722,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
 
     // SubItemValuePerItem
     {   // 3d
-      auto mesh                           = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -1855,7 +1855,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
       }
 
       {
-        auto other_mesh                           = MeshDataBaseForTests::get().cartesian2DMesh();
+        auto other_mesh = MeshDataBaseForTests::get().cartesian2DMesh()->get<Mesh<Connectivity<2>>>();
         const Connectivity<2>& other_connectivity = other_mesh->connectivity();
 
         FaceArray<DataType> other_shape{other_connectivity, 2};
@@ -1868,7 +1868,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
 
     // SubItemArrayPerItem
     {   // 3d
-      auto mesh                           = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto mesh                           = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
       std::string filename                = ParallelChecker::instance().filename();
       const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -2008,7 +2008,7 @@ TEST_CASE("ParallelChecker_read", "[dev]")
       }
 
       {
-        auto other_mesh                           = MeshDataBaseForTests::get().cartesian3DMesh();
+        auto other_mesh = MeshDataBaseForTests::get().cartesian3DMesh()->get<Mesh<Connectivity<3>>>();
         const Connectivity<3>& other_connectivity = other_mesh->connectivity();
 
         CellArray<double> other_shape{other_connectivity, 2};
diff --git a/tests/test_ParallelChecker_write.cpp b/tests/test_ParallelChecker_write.cpp
index 285485237..0d08696ad 100644
--- a/tests/test_ParallelChecker_write.cpp
+++ b/tests/test_ParallelChecker_write.cpp
@@ -131,7 +131,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
 
     // ItemValues
     {   // 1d
-      auto mesh = MeshDataBaseForTests::get().unordered1DMesh();
+      auto mesh = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
 
       const Connectivity<1>& connectivity = mesh->connectivity();
 
@@ -172,7 +172,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
     }
 
     {   // 2d
-      auto mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+      auto mesh = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
 
       const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -202,7 +202,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
     }
 
     {   // 3d
-      auto mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto mesh = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
 
       const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -244,7 +244,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
 
     // ItemArrays
     {   // 1d
-      auto mesh = MeshDataBaseForTests::get().unordered1DMesh();
+      auto mesh = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
 
       const Connectivity<1>& connectivity = mesh->connectivity();
 
@@ -285,7 +285,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
     }
 
     {   // 2d
-      auto mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+      auto mesh = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
 
       const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -315,7 +315,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
     }
 
     {   // 3d
-      auto mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto mesh = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
 
       const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -394,7 +394,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
 
     // ItemValues
     {   // 1d
-      auto mesh = MeshDataBaseForTests::get().unordered1DMesh();
+      auto mesh = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
 
       const Connectivity<1>& connectivity = mesh->connectivity();
 
@@ -424,7 +424,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
     }
 
     {   // 2d
-      auto mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+      auto mesh = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
 
       const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -454,7 +454,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
     }
 
     {   // 3d
-      auto mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto mesh = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
 
       const Connectivity<3>& connectivity = mesh->connectivity();
 
@@ -485,7 +485,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
 
     // ItemArrays
     {   // 1d
-      auto mesh = MeshDataBaseForTests::get().unordered1DMesh();
+      auto mesh = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>();
 
       const Connectivity<1>& connectivity = mesh->connectivity();
 
@@ -515,7 +515,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
     }
 
     {   // 2d
-      auto mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+      auto mesh = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>();
 
       const Connectivity<2>& connectivity = mesh->connectivity();
 
@@ -545,7 +545,7 @@ TEST_CASE("ParallelChecker_write", "[dev]")
     }
 
     {   // 3d
-      auto mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto mesh = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
 
       const Connectivity<3>& connectivity = mesh->connectivity();
 
diff --git a/tests/test_PrimalToDiamondDualConnectivityDataMapper.cpp b/tests/test_PrimalToDiamondDualConnectivityDataMapper.cpp
index f503eaac5..76882047e 100644
--- a/tests/test_PrimalToDiamondDualConnectivityDataMapper.cpp
+++ b/tests/test_PrimalToDiamondDualConnectivityDataMapper.cpp
@@ -20,7 +20,7 @@ TEST_CASE("PrimalToDiamondDualConnectivityDataMapper", "[mesh]")
     using ConnectivityType = Connectivity<Dimension>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().unordered1DMesh();
+    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().unordered1DMesh()->get<MeshType>();
     const ConnectivityType& primal_connectivity = mesh->connectivity();
 
     std::shared_ptr p_diamond_dual_connectivity =
@@ -47,7 +47,7 @@ TEST_CASE("PrimalToDiamondDualConnectivityDataMapper", "[mesh]")
     using ConnectivityType = Connectivity<Dimension>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid2DMesh();
+    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid2DMesh()->get<MeshType>();
     const ConnectivityType& primal_connectivity = mesh->connectivity();
 
     std::shared_ptr p_diamond_dual_connectivity =
@@ -226,7 +226,7 @@ TEST_CASE("PrimalToDiamondDualConnectivityDataMapper", "[mesh]")
     using ConnectivityType = Connectivity<Dimension>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid3DMesh();
+    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid3DMesh()->get<MeshType>();
     const ConnectivityType& primal_connectivity = mesh->connectivity();
 
     std::shared_ptr p_diamond_dual_connectivity =
diff --git a/tests/test_PrimalToDual1DConnectivityDataMapper.cpp b/tests/test_PrimalToDual1DConnectivityDataMapper.cpp
index 6bf365ec4..df4e58046 100644
--- a/tests/test_PrimalToDual1DConnectivityDataMapper.cpp
+++ b/tests/test_PrimalToDual1DConnectivityDataMapper.cpp
@@ -17,7 +17,7 @@ TEST_CASE("PrimalToDual1DConnectivityDataMapper", "[mesh]")
   using ConnectivityType = Connectivity<Dimension>;
   using MeshType         = Mesh<ConnectivityType>;
 
-  std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().unordered1DMesh();
+  std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().unordered1DMesh()->get<MeshType>();
   const ConnectivityType& primal_connectivity = mesh->connectivity();
 
   std::shared_ptr p_dual_1d_connectivity =
diff --git a/tests/test_PrimalToMedianDualConnectivityDataMapper.cpp b/tests/test_PrimalToMedianDualConnectivityDataMapper.cpp
index 6a753b49f..7c9a25d68 100644
--- a/tests/test_PrimalToMedianDualConnectivityDataMapper.cpp
+++ b/tests/test_PrimalToMedianDualConnectivityDataMapper.cpp
@@ -20,7 +20,7 @@ TEST_CASE("PrimalToMedianDualConnectivityDataMapper", "[mesh]")
     using ConnectivityType = Connectivity<Dimension>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().unordered1DMesh();
+    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().unordered1DMesh()->get<MeshType>();
     const ConnectivityType& primal_connectivity = mesh->connectivity();
 
     std::shared_ptr p_median_dual_connectivity =
@@ -47,7 +47,7 @@ TEST_CASE("PrimalToMedianDualConnectivityDataMapper", "[mesh]")
     using ConnectivityType = Connectivity<Dimension>;
     using MeshType         = Mesh<ConnectivityType>;
 
-    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid2DMesh();
+    std::shared_ptr<const MeshType> mesh        = MeshDataBaseForTests::get().hybrid2DMesh()->get<MeshType>();
     const ConnectivityType& primal_connectivity = mesh->connectivity();
 
     std::shared_ptr p_median_dual_connectivity =
diff --git a/tests/test_SubItemArrayPerItem.cpp b/tests/test_SubItemArrayPerItem.cpp
index ec4e06e0c..f027c56be 100644
--- a/tests/test_SubItemArrayPerItem.cpp
+++ b/tests/test_SubItemArrayPerItem.cpp
@@ -69,7 +69,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -192,7 +192,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -358,7 +358,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -555,7 +555,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -628,7 +628,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -700,7 +700,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -772,7 +772,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
         const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -883,7 +883,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
         const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -994,7 +994,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
         const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -1068,7 +1068,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
 
     SECTION("checking invalid table size in constructor")
     {
-      auto mesh_3d = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto mesh_3d = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
 
       const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -1090,7 +1090,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
diff --git a/tests/test_SubItemArrayPerItemUtils.cpp b/tests/test_SubItemArrayPerItemUtils.cpp
index d36829250..8d4c75167 100644
--- a/tests/test_SubItemArrayPerItemUtils.cpp
+++ b/tests/test_SubItemArrayPerItemUtils.cpp
@@ -23,7 +23,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
         const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -95,7 +95,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -127,7 +127,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -159,7 +159,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -194,7 +194,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -226,7 +226,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -258,7 +258,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -294,7 +294,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -324,7 +324,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name() + " for size_t data")
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -347,7 +347,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
 
         SECTION(named_mesh.name() + " for N^2 data")
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -373,7 +373,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
 
         SECTION(named_mesh.name() + " for float data")
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -417,7 +417,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name() + " for size_t data")
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -440,7 +440,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
 
         SECTION(named_mesh.name() + " for N^2x3 data")
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -466,7 +466,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]")
 
         SECTION(named_mesh.name() + " for R^2x3 data")
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
diff --git a/tests/test_SubItemArrayPerItemVariant.cpp b/tests/test_SubItemArrayPerItemVariant.cpp
index 6e3413aec..e40386701 100644
--- a/tests/test_SubItemArrayPerItemVariant.cpp
+++ b/tests/test_SubItemArrayPerItemVariant.cpp
@@ -11,7 +11,7 @@
 
 TEST_CASE("SubItemArrayPerItemVariant", "[mesh]")
 {
-  std::shared_ptr mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+  std::shared_ptr mesh = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
 
   const Connectivity<3>& connectivity = *mesh->shared_connectivity();
 
diff --git a/tests/test_SubItemValuePerItem.cpp b/tests/test_SubItemValuePerItem.cpp
index 349de7250..92569d982 100644
--- a/tests/test_SubItemValuePerItem.cpp
+++ b/tests/test_SubItemValuePerItem.cpp
@@ -79,7 +79,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -215,7 +215,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -391,7 +391,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -596,7 +596,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -712,7 +712,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -898,7 +898,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -1119,7 +1119,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -1164,7 +1164,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -1208,7 +1208,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -1254,7 +1254,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_3d = named_mesh.mesh();
+        auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
         const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -1353,7 +1353,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
         const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -1420,7 +1420,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
 
     SECTION("checking invalid array size in constructor")
     {
-      auto mesh_3d = MeshDataBaseForTests::get().hybrid3DMesh();
+      auto mesh_3d = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
 
       const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -1442,7 +1442,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
diff --git a/tests/test_SubItemValuePerItemUtils.cpp b/tests/test_SubItemValuePerItemUtils.cpp
index 353d7a950..ee73b6072 100644
--- a/tests/test_SubItemValuePerItemUtils.cpp
+++ b/tests/test_SubItemValuePerItemUtils.cpp
@@ -23,7 +23,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
     for (const auto& named_mesh : mesh_list) {
       SECTION(named_mesh.name())
       {
-        auto mesh_2d = named_mesh.mesh();
+        auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
         const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -90,7 +90,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -120,7 +120,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -150,7 +150,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -183,7 +183,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -213,7 +213,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -243,7 +243,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -278,7 +278,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name())
         {
-          auto mesh_1d = named_mesh.mesh();
+          auto mesh_1d = named_mesh.mesh()->get<Mesh<Connectivity<1>>>();
 
           const Connectivity<1>& connectivity = mesh_1d->connectivity();
 
@@ -307,7 +307,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name() + " for size_t data")
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -329,7 +329,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
 
         SECTION(named_mesh.name() + " for R^2 data")
         {
-          auto mesh_2d = named_mesh.mesh();
+          auto mesh_2d = named_mesh.mesh()->get<Mesh<Connectivity<2>>>();
 
           const Connectivity<2>& connectivity = mesh_2d->connectivity();
 
@@ -366,7 +366,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
       for (const auto& named_mesh : mesh_list) {
         SECTION(named_mesh.name() + " for size_t data")
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -388,7 +388,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
 
         SECTION(named_mesh.name() + " for N^2x3 data")
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
@@ -413,7 +413,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]")
 
         SECTION(named_mesh.name() + " for R^3x2 float")
         {
-          auto mesh_3d = named_mesh.mesh();
+          auto mesh_3d = named_mesh.mesh()->get<Mesh<Connectivity<3>>>();
 
           const Connectivity<3>& connectivity = mesh_3d->connectivity();
 
diff --git a/tests/test_SubItemValuePerItemVariant.cpp b/tests/test_SubItemValuePerItemVariant.cpp
index d36be5e42..01ff40651 100644
--- a/tests/test_SubItemValuePerItemVariant.cpp
+++ b/tests/test_SubItemValuePerItemVariant.cpp
@@ -11,7 +11,7 @@
 
 TEST_CASE("SubItemValuePerItemVariant", "[mesh]")
 {
-  std::shared_ptr mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+  std::shared_ptr mesh = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>();
 
   const Connectivity<3>& connectivity = *mesh->shared_connectivity();
 
diff --git a/tests/test_Synchronizer.cpp b/tests/test_Synchronizer.cpp
index fcad9e414..e14aff66a 100644
--- a/tests/test_Synchronizer.cpp
+++ b/tests/test_Synchronizer.cpp
@@ -28,7 +28,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 1;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().unordered1DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>()->connectivity();
 
       SECTION("synchonize NodeValue")
       {
@@ -136,7 +137,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 2;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().hybrid2DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>()->connectivity();
 
       SECTION("synchonize NodeValue")
       {
@@ -244,7 +246,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 3;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().hybrid3DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>()->connectivity();
 
       SECTION("synchonize NodeValue")
       {
@@ -366,7 +369,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 1;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().unordered1DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>()->connectivity();
 
       SECTION("synchonize NodeArray")
       {
@@ -498,7 +502,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 2;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().hybrid2DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>()->connectivity();
 
       SECTION("synchonize NodeArray")
       {
@@ -630,7 +635,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 3;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().hybrid3DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>()->connectivity();
 
       SECTION("synchonize NodeArray")
       {
@@ -789,7 +795,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 1;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().unordered1DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>()->connectivity();
 
       SECTION("synchonize NodeValuePerCell")
       {
@@ -1064,7 +1071,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 2;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().hybrid2DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>()->connectivity();
 
       SECTION("synchonize NodeValuePerCell")
       {
@@ -1517,7 +1525,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 3;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().hybrid3DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>()->connectivity();
 
       SECTION("synchonize NodeValuePerCell")
       {
@@ -2093,7 +2102,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 1;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().unordered1DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<Connectivity<1>>>()->connectivity();
 
       SECTION("synchonize NodeArrayPerCell")
       {
@@ -2398,7 +2408,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 2;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().hybrid2DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<Connectivity<2>>>()->connectivity();
 
       SECTION("synchonize NodeArrayPerCell")
       {
@@ -2901,7 +2912,8 @@ TEST_CASE("Synchronizer", "[mesh]")
       constexpr size_t Dimension = 3;
       using ConnectivityType     = Connectivity<Dimension>;
 
-      const ConnectivityType& connectivity = MeshDataBaseForTests::get().hybrid3DMesh()->connectivity();
+      const ConnectivityType& connectivity =
+        MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<Connectivity<3>>>()->connectivity();
 
       SECTION("synchonize NodeArrayPerCell")
       {
-- 
GitLab