diff --git a/dumux/discretization/cellcentered/mpfa/darcyslaw.hh b/dumux/discretization/cellcentered/mpfa/darcyslaw.hh
index 4f5f9d79b84b728f9aa1d5f44b2a0fe496e8513d..50335bfd9628b24839945db19a9def02c72c3326 100644
--- a/dumux/discretization/cellcentered/mpfa/darcyslaw.hh
+++ b/dumux/discretization/cellcentered/mpfa/darcyslaw.hh
@@ -107,16 +107,14 @@ class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
         using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume);
         using PrimaryIvLocalFaceData = typename PrimaryInteractionVolume::Traits::LocalFaceData;
         using PrimaryIvDataHandle = typename PrimaryInteractionVolume::Traits::DataHandle;
-        using PrimaryIvVector = typename PrimaryInteractionVolume::Traits::Vector;
-        using PrimaryIvMatrix = typename PrimaryInteractionVolume::Traits::Matrix;
-        using PrimaryIvTij = typename PrimaryIvMatrix::row_type;
+        using PrimaryIvCellVector = typename PrimaryInteractionVolume::Traits::MatVecTraits::CellVector;
+        using PrimaryIvTij = typename PrimaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type;
 
         using SecondaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume);
         using SecondaryIvLocalFaceData = typename SecondaryInteractionVolume::Traits::LocalFaceData;
         using SecondaryIvDataHandle = typename SecondaryInteractionVolume::Traits::DataHandle;
-        using SecondaryIvVector = typename SecondaryInteractionVolume::Traits::Vector;
-        using SecondaryIvMatrix = typename SecondaryInteractionVolume::Traits::Matrix;
-        using SecondaryIvTij = typename SecondaryIvMatrix::row_type;
+        using SecondaryIvCellVector = typename SecondaryInteractionVolume::Traits::MatVecTraits::CellVector;
+        using SecondaryIvTij = typename SecondaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type;
 
     public:
         // export the filler type
@@ -236,11 +234,11 @@ class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
         //! Coefficients for the cell (& Dirichlet) unknowns in flux expressions (secondary type)
         const SecondaryIvTij& advectionTijSecondaryIv() const { return *secondaryTij_; }
 
-        //! The cell (& Dirichlet) pressures within this interaction volume (primary type)
-        const PrimaryIvVector& pressuresPrimaryIv(unsigned int phaseIdx) const { return *primaryPj_[phaseIdx]; }
+        //! The cell (& maybe Dirichlet) pressures within this interaction volume (primary type)
+        const PrimaryIvCellVector& pressuresPrimaryIv(unsigned int phaseIdx) const { return *primaryPj_[phaseIdx]; }
 
-        //! The cell (& Dirichlet) pressures within this interaction volume (secondary type)
-        const SecondaryIvVector& pressuresSecondaryIv(unsigned int phaseIdx) const { return *secondaryPj_[phaseIdx]; }
+        //! The cell (& maybe Dirichlet) pressures within this interaction volume (secondary type)
+        const SecondaryIvCellVector& pressuresSecondaryIv(unsigned int phaseIdx) const { return *secondaryPj_[phaseIdx]; }
 
         //! The gravitational acceleration for a phase on this scvf
         Scalar gravity(unsigned int phaseIdx) const { return g_[phaseIdx]; }
@@ -262,8 +260,8 @@ class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
         const SecondaryIvTij* secondaryTij_;
 
         //! The interaction-volume wide phase pressures pj
-        std::array<const PrimaryIvVector*, numPhases> primaryPj_;
-        std::array<const SecondaryIvVector*, numPhases> secondaryPj_;
+        std::array<const PrimaryIvCellVector*, numPhases> primaryPj_;
+        std::array<const SecondaryIvCellVector*, numPhases> secondaryPj_;
 
         //! Gravitational flux contribution on this face
         std::array< Scalar, numPhases > g_;
diff --git a/dumux/discretization/cellcentered/mpfa/dualgridindexset.hh b/dumux/discretization/cellcentered/mpfa/dualgridindexset.hh
index 84aca7ed72008982cba4e459729476ca3919caa1..b9b95cbc5ffd6da967f48d40601b9b77f41de4d6 100644
--- a/dumux/discretization/cellcentered/mpfa/dualgridindexset.hh
+++ b/dumux/discretization/cellcentered/mpfa/dualgridindexset.hh
@@ -38,7 +38,7 @@ namespace Dumux
  * \brief Nodal index set for mpfa schemes, constructed
  *        around grid vertices.
  *
- * \tparam GI The type used for indices on the grid
+ * \tparam GV The grid view type
  * \tparam LI The type used for indexing in interaction volumes
  * \tparam dim The dimension of the grid
  * \tparam maxE The maximum admissible number of elements around vertices.
@@ -46,12 +46,16 @@ namespace Dumux
  *              This is only to be specified for network grids and defaults to 1
  *              for normal grids.
  */
-template< class GI, class LI, int dim, int maxE, int maxB = 2 >
+template< class GV, class LI, int dim, int maxE, int maxB = 2 >
 class CCMpfaDualGridNodalIndexSet
 {
+    using GI = typename GV::IndexSet::IndexType;
     using DimIndexVector = Dune::ReservedVector<GI, dim>;
 
 public:
+    //! Export the grid view type
+    using GridView = GV;
+
     //! Export the used index types
     using GridIndexType = GI;
     using LocalIndexType = LI;
diff --git a/dumux/discretization/cellcentered/mpfa/fickslaw.hh b/dumux/discretization/cellcentered/mpfa/fickslaw.hh
index ae3979d58deb66b2702ce536db2a6ae3cda9d59a..3f68da0dde36f2484cc5ce41f81a90690edccb13 100644
--- a/dumux/discretization/cellcentered/mpfa/fickslaw.hh
+++ b/dumux/discretization/cellcentered/mpfa/fickslaw.hh
@@ -105,16 +105,14 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
         using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume);
         using PrimaryIvLocalFaceData = typename PrimaryInteractionVolume::Traits::LocalFaceData;
         using PrimaryIvDataHandle = typename PrimaryInteractionVolume::Traits::DataHandle;
-        using PrimaryIvVector = typename PrimaryInteractionVolume::Traits::Vector;
-        using PrimaryIvMatrix = typename PrimaryInteractionVolume::Traits::Matrix;
-        using PrimaryIvTij = typename PrimaryIvMatrix::row_type;
+        using PrimaryIvCellVector = typename PrimaryInteractionVolume::Traits::MatVecTraits::CellVector;
+        using PrimaryIvTij = typename PrimaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type;
 
         using SecondaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume);
         using SecondaryIvLocalFaceData = typename SecondaryInteractionVolume::Traits::LocalFaceData;
         using SecondaryIvDataHandle = typename SecondaryInteractionVolume::Traits::DataHandle;
-        using SecondaryIvVector = typename SecondaryInteractionVolume::Traits::Vector;
-        using SecondaryIvMatrix = typename SecondaryInteractionVolume::Traits::Matrix;
-        using SecondaryIvTij = typename SecondaryIvMatrix::row_type;
+        using SecondaryIvCellVector = typename SecondaryInteractionVolume::Traits::MatVecTraits::CellVector;
+        using SecondaryIvTij = typename SecondaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type;
 
         static constexpr int dim = GridView::dimension;
         static constexpr int dimWorld = GridView::dimensionworld;
@@ -198,12 +196,12 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
         const SecondaryIvTij& diffusionTijSecondaryIv(unsigned int phaseIdx, unsigned int compIdx) const
         { return *secondaryTij_[phaseIdx][compIdx]; }
 
-        //! The cell (& Dirichlet) mole fractions within this interaction volume (primary type)
-        const PrimaryIvVector& moleFractionsPrimaryIv(unsigned int phaseIdx, unsigned int compIdx) const
+        //! The cell (& maybe Dirichlet) mole fractions within this interaction volume (primary type)
+        const PrimaryIvCellVector& moleFractionsPrimaryIv(unsigned int phaseIdx, unsigned int compIdx) const
         { return *primaryXj_[phaseIdx][compIdx]; }
 
-        //! The cell (& Dirichlet) mole fractions within this interaction volume (secondary type)
-        const SecondaryIvVector& moleFractionsSecondaryIv(unsigned int phaseIdx, unsigned int compIdx) const
+        //! The cell (& maybe Dirichlet) mole fractions within this interaction volume (secondary type)
+        const SecondaryIvCellVector& moleFractionsSecondaryIv(unsigned int phaseIdx, unsigned int compIdx) const
         { return *secondaryXj_[phaseIdx][compIdx]; }
 
         //! The stencils corresponding to the transmissibilities
@@ -217,12 +215,12 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
         std::array< std::array<const Stencil*, numComponents>, numPhases > stencil_;
 
         //! The transmissibilities such that f = Tij*xj
-        std::array< std::array<const PrimaryIvVector*, numComponents>, numPhases > primaryTij_;
-        std::array< std::array<const SecondaryIvVector*, numComponents>, numPhases > secondaryTij_;
+        std::array< std::array<const PrimaryIvCellVector*, numComponents>, numPhases > primaryTij_;
+        std::array< std::array<const SecondaryIvCellVector*, numComponents>, numPhases > secondaryTij_;
 
         //! The interaction-volume wide mole fractions xj
-        std::array< std::array<const PrimaryIvVector*, numComponents>, numPhases > primaryXj_;
-        std::array< std::array<const SecondaryIvVector*, numComponents>, numPhases > secondaryXj_;
+        std::array< std::array<const PrimaryIvCellVector*, numComponents>, numPhases > primaryXj_;
+        std::array< std::array<const SecondaryIvCellVector*, numComponents>, numPhases > secondaryXj_;
     };
 
 public:
diff --git a/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh b/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh
index 8b0863abf7f9375255d8a4ea22212f02d5a3b871..2f4735da25a26c47143f5b33f3a7fe1679bc0e03 100644
--- a/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh
+++ b/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh
@@ -431,8 +431,8 @@ private:
         using LambdaFactory = TensorLambdaFactory<TypeTag, DiscretizationMethods::CCMpfa>;
 
         // get instance of the interaction volume-local assembler
-        using IVTraits = typename InteractionVolume::Traits;
-        using IvLocalAssembler = InteractionVolumeAssembler< IVTraits, InteractionVolume::MpfaMethod >;
+        static constexpr MpfaMethods M = InteractionVolume::MpfaMethod;
+        using IvLocalAssembler = InteractionVolumeAssembler< Problem, FVElementGeometry, ElementVolumeVariables, M >;
         IvLocalAssembler localAssembler(problem(), fvGeometry(), elemVolVars());
 
         // Use different assembly if gravity is enabled
@@ -516,8 +516,8 @@ private:
         using LambdaFactory = TensorLambdaFactory<TypeTag, DiscretizationMethods::CCMpfa>;
 
         // get instance of the interaction volume-local assembler
-        using IVTraits = typename InteractionVolume::Traits;
-        using IvLocalAssembler = InteractionVolumeAssembler< IVTraits, InteractionVolume::MpfaMethod >;
+        static constexpr MpfaMethods M = InteractionVolume::MpfaMethod;
+        using IvLocalAssembler = InteractionVolumeAssembler< Problem, FVElementGeometry, ElementVolumeVariables, M >;
         IvLocalAssembler localAssembler(problem(), fvGeometry(), elemVolVars());
 
         // solve the local system subject to the tensor and update the handle
@@ -555,8 +555,8 @@ private:
         using LambdaFactory = TensorLambdaFactory<TypeTag, DiscretizationMethods::CCMpfa>;
 
         // get instance of the interaction volume-local assembler
-        using IVTraits = typename InteractionVolume::Traits;
-        using IvLocalAssembler = InteractionVolumeAssembler< IVTraits, InteractionVolume::MpfaMethod >;
+        static constexpr MpfaMethods M = InteractionVolume::MpfaMethod;
+        using IvLocalAssembler = InteractionVolumeAssembler< Problem, FVElementGeometry, ElementVolumeVariables, M >;
         IvLocalAssembler localAssembler(problem(), fvGeometry(), elemVolVars());
 
         if (forceUpdateAll || soldependentAdvection)
diff --git a/dumux/discretization/cellcentered/mpfa/fourierslaw.hh b/dumux/discretization/cellcentered/mpfa/fourierslaw.hh
index 56e3af6da2d0625c0aca32d27c8afbec6f26cb41..121de6a44c68bc791da278a8c49a626b231305a4 100644
--- a/dumux/discretization/cellcentered/mpfa/fourierslaw.hh
+++ b/dumux/discretization/cellcentered/mpfa/fourierslaw.hh
@@ -103,16 +103,14 @@ class FouriersLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
         using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume);
         using PrimaryIvLocalFaceData = typename PrimaryInteractionVolume::Traits::LocalFaceData;
         using PrimaryIvDataHandle = typename PrimaryInteractionVolume::Traits::DataHandle;
-        using PrimaryIvVector = typename PrimaryInteractionVolume::Traits::Vector;
-        using PrimaryIvMatrix = typename PrimaryInteractionVolume::Traits::Matrix;
-        using PrimaryIvTij = typename PrimaryIvMatrix::row_type;
+        using PrimaryIvCellVector = typename PrimaryInteractionVolume::Traits::MatVecTraits::CellVector;
+        using PrimaryIvTij = typename PrimaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type;
 
         using SecondaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume);
         using SecondaryIvLocalFaceData = typename SecondaryInteractionVolume::Traits::LocalFaceData;
         using SecondaryIvDataHandle = typename SecondaryInteractionVolume::Traits::DataHandle;
-        using SecondaryIvVector = typename SecondaryInteractionVolume::Traits::Vector;
-        using SecondaryIvMatrix = typename SecondaryInteractionVolume::Traits::Matrix;
-        using SecondaryIvTij = typename SecondaryIvMatrix::row_type;
+        using SecondaryIvCellVector = typename SecondaryInteractionVolume::Traits::MatVecTraits::CellVector;
+        using SecondaryIvTij = typename SecondaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type;
 
         static constexpr int dim = GridView::dimension;
         static constexpr int dimWorld = GridView::dimensionworld;
@@ -188,10 +186,10 @@ class FouriersLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
         const Stencil& heatConductionStencil() const { return *stencil_; }
 
         //! The cell (& Dirichlet) temperatures within this interaction volume (primary type)
-        const PrimaryIvVector& temperaturesPrimaryIv() const { return *primaryTj_; }
+        const PrimaryIvCellVector& temperaturesPrimaryIv() const { return *primaryTj_; }
 
         //! The cell (& Dirichlet) temperatures within this interaction volume (secondary type)
-        const SecondaryIvVector& temperaturesSecondaryIv() const { return *secondaryTj_; }
+        const SecondaryIvCellVector& temperaturesSecondaryIv() const { return *secondaryTj_; }
 
         //! In the interaction volume-local system of eq we have one unknown per face.
         //! On scvfs on this face, but in "outside" (neighbor) elements of it, we have
@@ -210,8 +208,8 @@ class FouriersLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
         const SecondaryIvTij* secondaryTij_;
 
         //! The interaction-volume wide temperature Tj
-        const PrimaryIvVector* primaryTj_;
-        const SecondaryIvVector* secondaryTj_;
+        const PrimaryIvCellVector* primaryTj_;
+        const SecondaryIvCellVector* secondaryTj_;
     };
 
 public:
diff --git a/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh b/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh
index a23d1674f7608d8b33e8531a429982d74023ac3a..ef2380333056368c0cbe57402df0934cf4abd0a4 100644
--- a/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh
+++ b/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh
@@ -346,6 +346,9 @@ public:
         std::cout << "Initializing of the connectivity map took " << timer.elapsed() << " seconds." << std::endl;
     }
 
+    //! Returns instance of the mpfa helper type
+    MpfaHelper mpfaHelper() const { return MpfaHelper(); }
+
     //! Get a sub control volume with a global scv index
     const SubControlVolume& scv(GridIndexType scvIdx) const { return scvs_[scvIdx]; }
 
@@ -689,6 +692,9 @@ public:
         std::cout << "Initializing of the connectivity map took " << timer.elapsed() << " seconds." << std::endl;
     }
 
+    //! Returns instance of the mpfa helper type
+    MpfaHelper mpfaHelper() const { return MpfaHelper(); }
+
     //! Returns the sub control volume face indices of an scv by global index.
     const std::vector<GridIndexType>& scvfIndicesOfScv(GridIndexType scvIdx) const
     { return scvfIndicesOfScv_[scvIdx]; }
diff --git a/dumux/discretization/cellcentered/mpfa/gridinteractionvolumeindexsets.hh b/dumux/discretization/cellcentered/mpfa/gridinteractionvolumeindexsets.hh
index 358e0b0fe1a2c7ec93329861d41835245293a866..9dea0f375c17ea722c5abdd68b0419e1f67e6950 100644
--- a/dumux/discretization/cellcentered/mpfa/gridinteractionvolumeindexsets.hh
+++ b/dumux/discretization/cellcentered/mpfa/gridinteractionvolumeindexsets.hh
@@ -25,7 +25,6 @@
 #define DUMUX_DISCRETIZATION_MPFA_O_GRIDINTERACTIONVOLUME_INDEXSETS_HH
 
 #include <memory>
-#include <dumux/common/properties.hh>
 
 #include "dualgridindexset.hh"
 
diff --git a/dumux/discretization/cellcentered/mpfa/helper.hh b/dumux/discretization/cellcentered/mpfa/helper.hh
index 9c7f47943e1a8a3bf2af30531446c9434156a1db..dac6e546245690ca97c9da50c658cfe2050b0581 100644
--- a/dumux/discretization/cellcentered/mpfa/helper.hh
+++ b/dumux/discretization/cellcentered/mpfa/helper.hh
@@ -32,7 +32,6 @@
 #include <dune/geometry/type.hh>
 #include <dune/geometry/referenceelements.hh>
 
-#include <dumux/common/properties.hh>
 #include <dumux/common/math.hh>
 
 namespace Dumux {
@@ -41,34 +40,22 @@ namespace Dumux {
  * \ingroup CCMpfaDiscretization
  * \brief Dimension-specific helper class to get data required for mpfa scheme.
  */
-template<class TypeTag, int dim, int dimWorld>
+template<class FVGridGeometry, int dim, int dimWorld>
 class MpfaDimensionHelper;
 
 /*!
  * \ingroup CCMpfaDiscretization
- * \brief  Dimension-specific helper class to get data required for mpfa scheme.
- *         Specialization for dim == 2 & dimWorld == 2
+ * \brief  Dimension-specific mpfa helper class for dim == 2 & dimWorld == 2
  */
-template<class TypeTag>
-class MpfaDimensionHelper<TypeTag, /*dim*/2, /*dimWorld*/2>
+template<class FVGridGeometry>
+class MpfaDimensionHelper<FVGridGeometry, /*dim*/2, /*dimWorld*/2>
 {
-    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
-    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView;
-    using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
+    using GridView = typename FVGridGeometry::GridView;
+    using CoordScalar = typename GridView::ctype;
+    using GlobalPosition = Dune::FieldVector<CoordScalar, GridView::dimensionworld>;
+
+    using SubControlVolumeFace = typename FVGridGeometry::SubControlVolumeFace;
     using ScvfCornerVector = typename SubControlVolumeFace::Traits::CornerStorage;
-    using InteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume);
-    using LocalScvType = typename InteractionVolume::Traits::LocalScvType;
-    using ScvBasis = typename LocalScvType::LocalBasis;
-
-    // We know that dim = 2 & dimworld = 2. However, the specialization for
-    // dim = 2 & dimWorld = 3 reuses some methods of this class, thus, we
-    // obtain the world dimension from the grid view here to get the
-    // GlobalPosition vector right. Be picky about the dimension though.
-    static_assert(GridView::dimension == 2, "The chosen mpfa helper expects a grid view with dim = 2");
-    static const int dim = 2;
-    static const int dimWorld = GridView::dimensionworld;
-    using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
 
     // Container to store the positions of intersections required for scvf
     // corner computation. In 2d, these are the center plus the two corners
@@ -80,9 +67,10 @@ public:
      *
      * \param scvBasis The basis of an scv
      */
+    template< class ScvBasis >
     static ScvBasis calculateInnerNormals(const ScvBasis& scvBasis)
     {
-        static const Dune::FieldMatrix<Scalar, dim, dim> R = {{0.0, 1.0}, {-1.0, 0.0}};
+        static const Dune::FieldMatrix<CoordScalar, 2, 2> R = {{0.0, 1.0}, {-1.0, 0.0}};
 
         ScvBasis innerNormals;
         R.mv(scvBasis[1], innerNormals[0]);
@@ -103,10 +91,11 @@ public:
      *
      * \param scvBasis The basis of an scv
      */
-    static typename LocalScvType::ctype calculateDetX(const ScvBasis& scvBasis)
+    template< class ScvBasis >
+    static CoordScalar calculateDetX(const ScvBasis& scvBasis)
     {
         using std::abs;
-        return abs(crossProduct<Scalar>(scvBasis[0], scvBasis[1]));
+        return abs(crossProduct<CoordScalar>(scvBasis[0], scvBasis[1]));
     }
 
     /*!
@@ -139,8 +128,9 @@ public:
      *
      * \param scvBasis The basis of an scv
      */
+    template< class ScvBasis >
     static bool isRightHandSystem(const ScvBasis& scvBasis)
-    { return !std::signbit(crossProduct<Scalar>(scvBasis[0], scvBasis[1])); }
+    { return !std::signbit(crossProduct<CoordScalar>(scvBasis[0], scvBasis[1])); }
 
     /*!
      * \brief Returns a vector containing the positions on a given intersection
@@ -164,7 +154,8 @@ public:
         p[0] = 0.0;
         for (unsigned int c = 0; c < numCorners; ++c)
         {
-            p[c+1] = eg.global(refElement.position(refElement.subEntity(indexInElement, 1, c, dim), dim));
+            // codim = 1, dim = 2
+            p[c+1] = eg.global(refElement.position(refElement.subEntity(indexInElement, 1, c, 2), 2));
             p[0] += p[c+1];
         }
         p[0] /= numCorners;
@@ -199,7 +190,7 @@ public:
      *
      * \param scvfCorners Container with the corners of the scvf
      */
-    static Scalar getScvfArea(const ScvfCornerVector& scvfCorners)
+    static CoordScalar getScvfArea(const ScvfCornerVector& scvfCorners)
     { return (scvfCorners[1]-scvfCorners[0]).two_norm(); }
 
     /*!
@@ -229,19 +220,15 @@ public:
 
 /*!
  * \ingroup CCMpfaDiscretization
- * \brief  Dimension-specific helper class to get data required for mpfa scheme.
- *         Specialization for dim == 2 & dimWorld == 2. Reuses some functionality
- *         of the specialization for dim = dimWorld = 2
+ * \brief  Dimension-specific mpfa helper class for dim == 2 & dimWorld == 2.
+ *         Reuses some functionality of the specialization for dim = dimWorld = 2
  */
-template<class TypeTag>
-class MpfaDimensionHelper<TypeTag, /*dim*/2, /*dimWorld*/3>
-                : public MpfaDimensionHelper<TypeTag, 2, 2>
+template<class FVGridGeometry>
+class MpfaDimensionHelper<FVGridGeometry, /*dim*/2, /*dimWorld*/3>
+      : public MpfaDimensionHelper<FVGridGeometry, 2, 2>
 {
-    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
-    using InteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume);
-    using LocalScvType = typename InteractionVolume::Traits::LocalScvType;
-    using ScvBasis = typename LocalScvType::LocalBasis;
-
+    using GridView = typename FVGridGeometry::GridView;
+    using CoordScalar = typename GridView::ctype;
 public:
 
     /*!
@@ -249,19 +236,20 @@ public:
      *
      * \param scvBasis The basis of an scv
      */
+    template< class ScvBasis >
     static ScvBasis calculateInnerNormals(const ScvBasis& scvBasis)
     {
         // compute vector normal to the basis plane
         const auto normal = [&] () {
-                                        auto n = crossProduct<Scalar>(scvBasis[0], scvBasis[1]);
+                                        auto n = crossProduct<CoordScalar>(scvBasis[0], scvBasis[1]);
                                         n /= n.two_norm();
                                         return n;
                                     } ();
 
         // compute inner normals using the normal vector
         ScvBasis innerNormals;
-        innerNormals[0] = crossProduct<Scalar>(scvBasis[1], normal);
-        innerNormals[1] = crossProduct<Scalar>(normal, scvBasis[0]);
+        innerNormals[0] = crossProduct<CoordScalar>(scvBasis[1], normal);
+        innerNormals[1] = crossProduct<CoordScalar>(normal, scvBasis[0]);
 
         return innerNormals;
     }
@@ -274,10 +262,11 @@ public:
      *
      * \param scvBasis The basis of an scv
      */
-    static typename LocalScvType::ctype calculateDetX(const ScvBasis& scvBasis)
+    template< class ScvBasis >
+    static CoordScalar calculateDetX(const ScvBasis& scvBasis)
     {
         using std::abs;
-        return abs(crossProduct<Scalar>(scvBasis[0], scvBasis[1]).two_norm());
+        return abs(crossProduct<CoordScalar>(scvBasis[0], scvBasis[1]).two_norm());
     }
 
     /*!
@@ -287,32 +276,24 @@ public:
      *
      * \param scvBasis The basis of an scv
      */
-    static bool isRightHandSystem(const ScvBasis& scvBasis)
-    { return true; }
+    template< class ScvBasis >
+    static constexpr bool isRightHandSystem(const ScvBasis& scvBasis) { return true; }
 };
 /*!
  * \ingroup CCMpfaDiscretization
- * \brief  Dimension-specific helper class to get data required for mpfa scheme.
- *         Specialization for dim == 3 & dimWorld == 3.
+ * \brief   Dimension-specific mpfa helper class for dim == 3 & dimWorld == 3.
+ *
  */
-template<class TypeTag>
-class MpfaDimensionHelper<TypeTag, /*dim*/3, /*dimWorld*/3>
+template<class FVGridGeometry>
+class MpfaDimensionHelper<FVGridGeometry, /*dim*/3, /*dimWorld*/3>
 {
-    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
-    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView;
-    using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
+    using SubControlVolumeFace = typename FVGridGeometry::SubControlVolumeFace;
     using ScvfCornerVector = typename SubControlVolumeFace::Traits::CornerStorage;
-    using InteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume);
-    using LocalScvType = typename InteractionVolume::Traits::LocalScvType;
-    using ScvBasis = typename LocalScvType::LocalBasis;
 
     // Be picky about the dimensions
-    static_assert(GridView::dimension == 3 && GridView::dimensionworld == 3,
-                  "The chosen mpfa helper expects a grid view with dim = 3 & dimWorld = 3");
-    static const int dim = 3;
-    static const int dimWorld = 3;
-    using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
+    using GridView = typename FVGridGeometry::GridView;
+    using CoordScalar = typename GridView::ctype;
+    using GlobalPosition = Dune::FieldVector<CoordScalar, /*dimworld*/3>;
 
     // container to store the positions of intersections required for
     // scvf corner computation. Maximum number of points needed is 9
@@ -326,13 +307,14 @@ public:
      *
      * \param scvBasis The basis of an scv
      */
+    template< class ScvBasis >
     static ScvBasis calculateInnerNormals(const ScvBasis& scvBasis)
     {
         ScvBasis innerNormals;
 
-        innerNormals[0] = crossProduct<Scalar>(scvBasis[1], scvBasis[2]);
-        innerNormals[1] = crossProduct<Scalar>(scvBasis[2], scvBasis[0]);
-        innerNormals[2] = crossProduct<Scalar>(scvBasis[0], scvBasis[1]);
+        innerNormals[0] = crossProduct<CoordScalar>(scvBasis[1], scvBasis[2]);
+        innerNormals[1] = crossProduct<CoordScalar>(scvBasis[2], scvBasis[0]);
+        innerNormals[2] = crossProduct<CoordScalar>(scvBasis[0], scvBasis[1]);
 
         if (!isRightHandSystem(scvBasis))
         {
@@ -350,10 +332,11 @@ public:
      *
      * \param scvBasis The basis of an scv
      */
-    static typename LocalScvType::ctype calculateDetX(const ScvBasis& scvBasis)
+    template< class ScvBasis >
+    static CoordScalar calculateDetX(const ScvBasis& scvBasis)
     {
         using std::abs;
-        return abs(tripleProduct<Scalar>(scvBasis[0], scvBasis[1], scvBasis[2]));
+        return abs(tripleProduct<CoordScalar>(scvBasis[0], scvBasis[1], scvBasis[2]));
     }
 
     /*!
@@ -396,8 +379,9 @@ public:
      *
      * \param scvBasis The basis of an scv
      */
+    template< class ScvBasis >
     static bool isRightHandSystem(const ScvBasis& scvBasis)
-    { return !std::signbit(tripleProduct<Scalar>(scvBasis[0], scvBasis[1], scvBasis[2])); }
+    { return !std::signbit(tripleProduct<CoordScalar>(scvBasis[0], scvBasis[1], scvBasis[2])); }
 
     /*!
      * \brief Returns a vector containing the positions on a given intersection
@@ -424,7 +408,8 @@ public:
         p[0] = 0.0;
         for (unsigned int c = 0; c < numCorners; ++c)
         {
-            p[c+1] = eg.global(refElement.position(refElement.subEntity(indexInElement, 1, c, dim), dim));
+            // codim = 1, dim = 3
+            p[c+1] = eg.global(refElement.position(refElement.subEntity(indexInElement, 1, c, 3), 3));
             p[0] += p[c+1];
         }
         p[0] /= numCorners;
@@ -457,9 +442,8 @@ public:
                 return p;
             }
             default:
-                DUNE_THROW(Dune::NotImplemented, "Mpfa scvf corners for dim = " << dim
-                                                              << ", dimWorld = " << dimWorld
-                                                              << ", corners = " << numCorners);
+                DUNE_THROW(Dune::NotImplemented,
+                           "Mpfa scvf corners for dim = 3, dimWorld = 3, corners = " << numCorners);
         }
     }
 
@@ -515,9 +499,8 @@ public:
                                           p[map[cornerIdx][3]]} );
             }
             default:
-                DUNE_THROW(Dune::NotImplemented, "Mpfa scvf corners for dim = " << dim
-                                                              << ", dimWorld = " << dimWorld
-                                                              << ", corners = " << numIntersectionCorners);
+                DUNE_THROW(Dune::NotImplemented,
+                           "Mpfa scvf corners for dim = 3, dimWorld = 3, corners = " << numIntersectionCorners);
         }
     }
 
@@ -526,7 +509,7 @@ public:
      *
      * \param scvfCorners Container with the corners of the scvf
      */
-    static Scalar getScvfArea(const ScvfCornerVector& scvfCorners)
+    static CoordScalar getScvfArea(const ScvfCornerVector& scvfCorners)
     {
         // after Wolfram alpha quadrilateral area
         return 0.5*Dumux::crossProduct(scvfCorners[3]-scvfCorners[0], scvfCorners[2]-scvfCorners[1]).two_norm();
@@ -566,26 +549,26 @@ public:
 /*!
  * \ingroup CCMpfaDiscretization
  * \brief Helper class to get the required information on an interaction volume.
- *        Specializations depending on the method and dimension are provided.
+ *
+ * \tparam FVGridGeometry The finite volume grid geometry
  */
-template<class TypeTag, int dim, int dimWorld>
-class CCMpfaHelperImplementation : public MpfaDimensionHelper<TypeTag, dim, dimWorld>
+template<class FVGridGeometry>
+class CCMpfaHelper : public MpfaDimensionHelper<FVGridGeometry,
+                                                FVGridGeometry::GridView::dimension,
+                                                FVGridGeometry::GridView::dimensionworld>
 {
-    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    using PrimaryInteractionVolume = typename FVGridGeometry::GridIVIndexSets::PrimaryInteractionVolume;
+    using SecondaryInteractionVolume = typename FVGridGeometry::GridIVIndexSets::SecondaryInteractionVolume;
 
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
-    using Element = typename GridView::template Codim<0>::Entity;
-    using IndexType = typename GridView::IndexSet::IndexType;
-
-    using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume);
-    using SecondaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume);
-
-    using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
     using VertexMapper = typename FVGridGeometry::VertexMapper;
     using FVElementGeometry = typename FVGridGeometry::LocalView;
     using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
     using ScvfCornerVector = typename SubControlVolumeFace::Traits::CornerStorage;
 
+    using GridView = typename FVGridGeometry::GridView;
+    static constexpr int dim = GridView::dimension;
+    static constexpr int dimWorld = GridView::dimensionworld;
+
     using CoordScalar = typename GridView::ctype;
     using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
     using ReferenceElements = typename Dune::ReferenceElements<CoordScalar, dim>;
@@ -597,14 +580,17 @@ public:
      * \param scvfCorners Container with the corners of the scvf
      * \param q Parameterization of the integration point on the scvf
      */
+    template< class Scalar >
     static GlobalPosition getScvfIntegrationPoint(const ScvfCornerVector& scvfCorners, Scalar q)
     {
-        // scvfs in 3d are always quadrilaterals
         // ordering -> first corner: facet center, last corner: vertex
         if (q == 0.0)
             return scvfCorners[0];
-        const auto d = [&] () { auto tmp = scvfCorners.back() - scvfCorners.front(); tmp *= q; return tmp; } ();
-        return scvfCorners[0] + d;
+
+        auto ip = scvfCorners.back() - scvfCorners.front();
+        ip *= q;
+        ip += scvfCorners[0];
+        return ip;
     }
 
     // returns a vector which maps true to each vertex on processor boundaries and false otherwise
@@ -617,7 +603,7 @@ public:
         if (Dune::MPIHelper::getCollectiveCommunication().size() == 1)
             return ghostVertices;
 
-        // mpfa methods can not yet handle ghost cells
+        // mpfa methods cannot yet handle ghost cells
         if (gridView.ghostSize(0) > 0)
             DUNE_THROW(Dune::InvalidStateException, "Mpfa methods in parallel do not work with ghost cells. Use overlap cells instead.");
 
@@ -660,16 +646,6 @@ public:
     { return std::find(vector.begin(), vector.end(), value) != vector.end(); }
 };
 
-/*!
- * \ingroup CCMpfaDiscretization
- * \brief Helper class to obtain data required for mpfa methods.
- *        It inherits from dimension-, dimensionworld- and method-specific implementations.
- */
-template<class TypeTag>
-using CCMpfaHelper = CCMpfaHelperImplementation<TypeTag,
-                                                GET_PROP_TYPE(TypeTag, GridView)::dimension,
-                                                GET_PROP_TYPE(TypeTag, GridView)::dimensionworld>;
-
 } // end namespace Dumux
 
 #endif
diff --git a/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh b/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh
index a4600b12b58ae2db93633b5c1936d066910cdbab..d55a189c3816ff7a69bfa918ea232372ce2ab572 100644
--- a/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh
+++ b/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh
@@ -26,8 +26,6 @@
 
 #include <dune/common/exceptions.hh>
 
-#include <dumux/common/properties.hh>
-
 namespace Dumux
 {
 
@@ -39,21 +37,11 @@ namespace Dumux
  *        The traits should contain the following type definitions:
  *
  * \code
- * //! export the problem type (needed for iv-local assembly)
- * using Problem = ...;
- * //! export the type of the local view on the finite volume grid geometry
- * using FVElementGeometry = ...;
- * //! export the type of the local view on the grid volume variables
- * using ElementVolumeVariables = ...;
  * //! export the type of grid view
  * using GridView = ...;
  * //! export the type used for scalar values
  * using ScalarType = ...;
- * //! export the type of the mpfa helper class
- * using MpfaHelper = ...;
  * //! export the type used for local indices
- * using LocalIndexType = ...;
- * //! export the type for the interaction volume index set
  * using IndexSet = ...;
  * //! export the type of interaction-volume local scvs
  * using LocalScvType = ...;
@@ -61,10 +49,8 @@ namespace Dumux
  * using LocalScvfType = ...;
  * //! export the type of used for the iv-local face data
  * using LocalFaceData = ...;
- * //! export the type used for iv-local matrices
- * using Matrix = ...;
- * //! export the type used for iv-local vectors
- * using Vector = ...;
+ * //! export the matrix/vector type traits to be used by the iv
+ * using MatVecTraits = ...;
  * //! export the data handle type for this iv
  * using DataHandle = ...;
  * \endcode
@@ -78,25 +64,26 @@ namespace Dumux
  * \tparam Impl The actual implementation of the interaction volume
  * \tparam T The traits class to be used
  */
-template< class Impl, class T>
+template< class Impl, class T >
 class CCMpfaInteractionVolumeBase
 {
     // Curiously recurring template pattern
     Impl& asImp() { return static_cast<Impl&>(*this); }
     const Impl& asImp() const { return static_cast<const Impl&>(*this); }
 
-    using Problem = typename T::Problem;
-    using FVElementGeometry = typename T::FVElementGeometry;
-    using ElementVolumeVariables = typename T::ElementVolumeVariables;
-
     using GridView = typename T::GridView;
     using Element = typename GridView::template Codim<0>::Entity;
 
+    using LocalIndexType = typename T::IndexSet::LocalIndexType;
+    using LocalScvType = typename T::LocalScvType;
+    using LocalScvfType = typename T::LocalScvfType;
+
 public:
     //! state the traits type publicly
     using Traits = T;
 
     //! Prepares everything for the assembly
+    template< class Problem, class FVElementGeometry >
     void setUpLocalScope(const typename Traits::IndexSet& indexSet,
                          const Problem& problem,
                          const FVElementGeometry& fvGeometry)
@@ -124,16 +111,13 @@ public:
     const typename Traits::IndexSet::GridStencilType& stencil() const { return asImp().stencil(); }
 
     //! returns the local scvf entity corresponding to a given iv-local scvf idx
-    const typename Traits::LocalScvfType& localScvf(typename Traits::LocalIndexType ivLocalScvfIdx) const
-    { return asImp().localScvf(ivLocalScvfIdx); }
+    const LocalScvfType& localScvf(LocalIndexType ivLocalScvfIdx) const { return asImp().localScvf(ivLocalScvfIdx); }
 
     //! returns the local scv entity corresponding to a given iv-local scv idx
-    const typename Traits::LocalScvType& localScv(typename Traits::LocalIndexType ivLocalScvIdx) const
-    { return asImp().localScv(ivLocalScvIdx); }
+    const LocalScvType& localScv(LocalIndexType ivLocalScvIdx) const { return asImp().localScv(ivLocalScvIdx); }
 
     //! returns the element in which the scv with the given local idx is embedded in
-    const Element& element(typename Traits::LocalIndexType ivLocalScvIdx) const
-    { return asImp().element(); }
+    const Element& element(LocalIndexType ivLocalScvIdx) const { return asImp().element(); }
 
     //! returns the number of interaction volumes living around a vertex
     template< class NodalIndexSet >
diff --git a/dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh b/dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh
index 025154b7f9a042f990e029b7d2a61ddc6c731482..72e2ddc632184a61f1083d35e6d09501218890b4 100644
--- a/dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh
+++ b/dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh
@@ -26,7 +26,8 @@
 
 #include <vector>
 
-#include <dumux/common/properties.hh>
+#include <dune/common/dynvector.hh>
+
 #include <dumux/common/parameters.hh>
 #include <dumux/common/matrixvectorhelper.hh>
 
@@ -42,26 +43,26 @@ public:
 };
 
 //! Data handle for quantities related to advection
-template<class TypeTag, class M, class V, class LI, bool EnableAdvection>
+template<class MatVecTraits, class PhysicsTraits, bool EnableAdvection>
 class AdvectionDataHandle
 {
     // export matrix & vector types from interaction volume
-    using Matrix = M;
-    using Vector = V;
-    using LocalIndexType = LI;
-    using Scalar = typename Vector::value_type;
-
-    using OutsideDataContainer = std::vector< std::vector<Vector> >;
+    using AMatrix = typename MatVecTraits::AMatrix;
+    using CMatrix = typename MatVecTraits::CMatrix;
+    using TMatrix = typename MatVecTraits::TMatrix;
+    using CellVector = typename MatVecTraits::CellVector;
+    using FaceVector = typename MatVecTraits::FaceVector;
+    using FaceScalar = typename FaceVector::value_type;
+    using OutsideGravityStorage = std::vector< Dune::DynamicVector<FaceScalar> >;
 
-    static constexpr int dim = GET_PROP_TYPE(TypeTag, GridView)::dimension;
-    static constexpr int dimWorld = GET_PROP_TYPE(TypeTag, GridView)::dimensionworld;
-    static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases);
+    static constexpr int numPhases = PhysicsTraits::numPhases;
 
 public:
 
     //! prepare data handle for subsequent fill (normal grids)
-    template< class InteractionVolume, int d = dim, int dw = dimWorld, std::enable_if_t<(d==dw), int> = 0>
-    void resize(const InteractionVolume& iv)
+    template< class IV,
+              std::enable_if_t<(IV::Traits::GridView::dimension==IV::Traits::GridView::dimensionworld), int> = 0>
+    void resize(const IV& iv)
     {
         // resize transmissibility matrix & pressure vectors
         resizeMatrix(T_, iv.numFaces(), iv.numKnowns());
@@ -69,7 +70,7 @@ public:
             resizeVector(p_[pIdx], iv.numKnowns());
 
         // maybe resize gravity container
-        static const bool enableGravity = getParamFromGroup<bool>(GET_PROP_VALUE(TypeTag, ModelParameterGroup), "Problem.EnableGravity");
+        static const bool enableGravity = getParam<bool>("Problem.EnableGravity");
         if (enableGravity)
         {
             resizeMatrix(CA_, iv.numFaces(), iv.numUnknowns());
@@ -80,11 +81,13 @@ public:
 
 
     //! prepare data handle for subsequent fill (surface grids)
-    template< class InteractionVolume, int d = dim, int dw = dimWorld, std::enable_if_t<(d<dw), int> = 0>
-    void resize(const InteractionVolume& iv)
+    template< class IV,
+              std::enable_if_t<(IV::Traits::GridView::dimension<IV::Traits::GridView::dimensionworld), int> = 0>
+    void resize(const IV& iv)
     {
-        static const bool enableGravity = getParamFromGroup<bool>(GET_PROP_VALUE(TypeTag, ModelParameterGroup), "Problem.EnableGravity");
+        using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType;
 
+        static const bool enableGravity = getParam<bool>("Problem.EnableGravity");
         if (!enableGravity)
         {
             resizeMatrix(T_, iv.numFaces(), iv.numKnowns());
@@ -129,66 +132,61 @@ public:
     }
 
     //! Access to the iv-wide pressure of one phase
-    const Vector& pressures(unsigned int pIdx) const { return p_[pIdx]; }
-    Vector& pressures(unsigned int pIdx) { return p_[pIdx]; }
+    const CellVector& pressures(unsigned int pIdx) const { return p_[pIdx]; }
+    CellVector& pressures(unsigned int pIdx) { return p_[pIdx]; }
 
     //! Access to the gravitational flux contributions for one phase
-    const Vector& gravity(unsigned int pIdx) const { return g_[pIdx]; }
-    Vector& gravity(unsigned int pIdx) { return g_[pIdx]; }
+    const FaceVector& gravity(unsigned int pIdx) const { return g_[pIdx]; }
+    FaceVector& gravity(unsigned int pIdx) { return g_[pIdx]; }
 
     //! Access to the gravitational flux contributions for all phases
-    const std::array< Vector, numPhases >& gravity() const { return g_; }
-    std::array< Vector, numPhases >& gravity() { return g_; }
+    const std::array< FaceVector, numPhases >& gravity() const { return g_; }
+    std::array< FaceVector, numPhases >& gravity() { return g_; }
 
     //! Projection matrix for gravitational acceleration
-    const Matrix& advectionCA() const { return CA_; }
-    Matrix& advectionCA() { return CA_; }
+    const CMatrix& advectionCA() const { return CA_; }
+    CMatrix& advectionCA() { return CA_; }
 
     //! Additional projection matrix needed on surface grids
-    const Matrix& advectionA() const { return A_; }
-    Matrix& advectionA() { return A_; }
+    const AMatrix& advectionA() const { return A_; }
+    AMatrix& advectionA() { return A_; }
 
     //! The transmissibilities associated with advective fluxes
-    const Matrix& advectionT() const { return T_; }
-    Matrix& advectionT() { return T_; }
+    const TMatrix& advectionT() const { return T_; }
+    TMatrix& advectionT() { return T_; }
 
     //! The transmissibilities for "outside" faces (used on surface grids)
-    const std::vector< std::vector<Vector> >& advectionTout() const { return outsideT_; }
-    std::vector< std::vector<Vector> >& advectionTout() { return outsideT_; }
+    const std::vector< std::vector<CellVector> >& advectionTout() const { return outsideT_; }
+    std::vector< std::vector<CellVector> >& advectionTout() { return outsideT_; }
 
     //! The gravitational acceleration for "outside" faces (used on surface grids)
-    const std::array< std::vector<Vector>, numPhases >& gravityOutside() const { return outsideG_; }
-    std::array< std::vector<Vector>, numPhases >& gravityOutside() { return outsideG_; }
+    const std::array< OutsideGravityStorage, numPhases >& gravityOutside() const { return outsideG_; }
+    std::array< OutsideGravityStorage, numPhases >& gravityOutside() { return outsideG_; }
 
     //! The gravitational acceleration for one phase on "outside" faces (used on surface grids)
-    const std::vector<Vector>& gravityOutside(unsigned int pIdx) const { return outsideG_[pIdx]; }
-    std::vector<Vector>& gravityOutside(unsigned int pIdx) { return outsideG_[pIdx]; }
+    const OutsideGravityStorage& gravityOutside(unsigned int pIdx) const { return outsideG_[pIdx]; }
+    OutsideGravityStorage& gravityOutside(unsigned int pIdx) { return outsideG_[pIdx]; }
 
 private:
-    //! advection-related variables
-    Matrix T_;                                               //!< The transmissibilities such that f_i = T_ij*p_j
-    Matrix CA_;                                              //!< Matrix to project gravitational acceleration to all scvfs
-    Matrix A_;                                               //!< Matrix additionally needed for the projection on surface grids
-    std::array< Vector, numPhases > p_;                      //!< The interaction volume-wide phase pressures
-    std::array< Vector, numPhases > g_;                      //!< The gravitational acceleration at each scvf (only for enabled gravity)
-    std::vector< std::vector<Vector> > outsideT_;            //!< The transmissibilities for "outside" faces (only on surface grids)
-    std::array< std::vector<Vector>, numPhases > outsideG_;  //!< The gravitational acceleration on "outside" faces (only on surface grids)
+    TMatrix T_;                                       //!< The transmissibilities such that f_i = T_ij*p_j
+    CMatrix CA_;                                      //!< Matrix to project gravitational acceleration to all scvfs
+    AMatrix A_;                                       //!< Matrix additionally needed for the projection on surface grids
+    std::array< CellVector, numPhases > p_;           //!< The interaction volume-wide phase pressures
+    std::array< FaceVector, numPhases > g_;           //!< The gravitational acceleration at each scvf (only for enabled gravity)
+    std::vector< std::vector<CellVector> > outsideT_; //!< The transmissibilities for "outside" faces (only on surface grids)
+    std::array< OutsideGravityStorage, numPhases > outsideG_;  //!< The gravitational acceleration on "outside" faces (only on surface grids)
 };
 
 //! Data handle for quantities related to diffusion
-template<class TypeTag, class M, class V, class LI, bool EnableDiffusion>
+template<class MatVecTraits, class PhysicsTraits, bool EnableDiffusion>
 class DiffusionDataHandle
 {
-    // export matrix & vector types from interaction volume
-    using Matrix = M;
-    using Vector = V;
-    using OutsideTContainer = std::vector< std::vector<Vector> >;
-
-    static constexpr int dim = GET_PROP_TYPE(TypeTag, GridView)::dimension;
-    static constexpr int dimWorld = GET_PROP_TYPE(TypeTag, GridView)::dimensionworld;
+    using TMatrix = typename MatVecTraits::TMatrix;
+    using CellVector = typename MatVecTraits::CellVector;
+    using OutsideTContainer = std::vector< std::vector<CellVector> >;
 
-    static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases);
-    static constexpr int numComponents = GET_PROP_VALUE(TypeTag, NumComponents);
+    static constexpr int numPhases = PhysicsTraits::numPhases;
+    static constexpr int numComponents = PhysicsTraits::numComponents;
 
 public:
     //! diffusion caches need to set phase and component index
@@ -203,20 +201,17 @@ public:
         {
             for (unsigned int cIdx = 0; cIdx < numComponents; ++cIdx)
             {
-                using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
-                if (cIdx == FluidSystem::getMainComponent(pIdx))
-                    continue;
-
                 // resize transmissibility matrix & mole fraction vector
                 resizeMatrix(T_[pIdx][cIdx], iv.numFaces(), iv.numKnowns());
                 resizeVector(xj_[pIdx][cIdx], iv.numKnowns());
 
                 // resize outsideTij on surface grids
-                if (dim < dimWorld)
+                using GridView = typename InteractionVolume::Traits::GridView;
+                if (int(GridView::dimension) < int(GridView::dimensionworld))
                 {
                     outsideT_[pIdx][cIdx].resize(iv.numFaces());
 
-                    using LocalIndexType = typename InteractionVolume::Traits::LocalIndexType;
+                    using LocalIndexType = typename InteractionVolume::Traits::IndexSet::LocalIndexType;
                     for (LocalIndexType i = 0; i < iv.numFaces(); ++i)
                     {
                         const auto numNeighbors = iv.localScvf(i).neighboringLocalScvIndices().size() - 1;
@@ -230,12 +225,12 @@ public:
     }
 
     //! Access to the iv-wide mole fractions of a component in one phase
-    const Vector& moleFractions(unsigned int pIdx, unsigned int compIdx) const { return xj_[pIdx][compIdx]; }
-    Vector& moleFractions(unsigned int pIdx, unsigned int compIdx) { return xj_[pIdx][compIdx]; }
+    const CellVector& moleFractions(unsigned int pIdx, unsigned int compIdx) const { return xj_[pIdx][compIdx]; }
+    CellVector& moleFractions(unsigned int pIdx, unsigned int compIdx) { return xj_[pIdx][compIdx]; }
 
     //! The transmissibilities associated with diffusive fluxes
-    const Matrix& diffusionT() const { return T_[phaseIdx_][compIdx_]; }
-    Matrix& diffusionT() { return T_[phaseIdx_][compIdx_]; }
+    const TMatrix& diffusionT() const { return T_[phaseIdx_][compIdx_]; }
+    TMatrix& diffusionT() { return T_[phaseIdx_][compIdx_]; }
 
     //! The transmissibilities for "outside" faces (used on surface grids)
     const OutsideTContainer& diffusionTout() const { return outsideT_[phaseIdx_][compIdx_]; }
@@ -243,22 +238,19 @@ public:
 
 private:
     //! diffusion-related variables
-    unsigned int phaseIdx_;                                         //!< The phase index set for the context
-    unsigned int compIdx_;                                          //!< The component index set for the context
-    std::array< std::array<Matrix, numComponents>, numPhases > T_;  //!< The transmissibilities such that f_i = T_ij*x_j
-    std::array< std::array<Vector, numComponents>, numPhases > xj_; //!< The interaction volume-wide mole fractions
+    unsigned int phaseIdx_;                                             //!< The phase index set for the context
+    unsigned int compIdx_;                                              //!< The component index set for the context
+    std::array< std::array<TMatrix, numComponents>, numPhases > T_;     //!< The transmissibilities such that f_i = T_ij*x_j
+    std::array< std::array<CellVector, numComponents>, numPhases > xj_; //!< The interaction volume-wide mole fractions
     std::array< std::array<OutsideTContainer, numComponents>, numPhases> outsideT_;
 };
 
 //! Data handle for quantities related to heat conduction
-template<class TypeTag, class M, class V, class LI, bool EnableHeatConduction>
+template<class MatVecTraits, class PhysicsTraits, bool enableHeatConduction>
 class HeatConductionDataHandle
 {
-    using Matrix = M;
-    using Vector = V;
-
-    static constexpr int dim = GET_PROP_TYPE(TypeTag, GridView)::dimension;
-    static constexpr int dimWorld = GET_PROP_TYPE(TypeTag, GridView)::dimensionworld;
+    using TMatrix = typename MatVecTraits::TMatrix;
+    using CellVector = typename MatVecTraits::CellVector;
 
 public:
     //! prepare data handle for subsequent fill
@@ -270,11 +262,12 @@ public:
         resizeVector(Tj_, iv.numKnowns());
 
         //! resize outsideTij on surface grids
-        if (dim < dimWorld)
+        using GridView = typename InteractionVolume::Traits::GridView;
+        if (int(GridView::dimension) < int(GridView::dimensionworld))
         {
             outsideT_.resize(iv.numFaces());
 
-            using LocalIndexType = typename InteractionVolume::Traits::LocalIndexType;
+            using LocalIndexType = typename InteractionVolume::Traits::IndexSet::LocalIndexType;
             for (LocalIndexType i = 0; i < iv.numFaces(); ++i)
             {
                 const auto numNeighbors = iv.localScvf(i).neighboringLocalScvIndices().size() - 1;
@@ -286,49 +279,47 @@ public:
     }
 
     //! Access to the iv-wide temperatures
-    const Vector& temperatures() const { return Tj_; }
-    Vector& temperatures() { return Tj_; }
+    const CellVector& temperatures() const { return Tj_; }
+    CellVector& temperatures() { return Tj_; }
 
     //! The transmissibilities associated with conductive fluxes
-    const Matrix& heatConductionT() const { return T_; }
-    Matrix& heatConductionT() { return T_; }
+    const TMatrix& heatConductionT() const { return T_; }
+    TMatrix& heatConductionT() { return T_; }
 
     //! The transmissibilities for "outside" faces (used on surface grids)
-    const std::vector< std::vector<Vector> >& heatConductionTout() const { return outsideT_; }
-    std::vector< std::vector<Vector> >& heatConductionTout() { return outsideT_; }
+    const std::vector< std::vector<CellVector> >& heatConductionTout() const { return outsideT_; }
+    std::vector< std::vector<CellVector> >& heatConductionTout() { return outsideT_; }
 
 private:
     // heat conduction-related variables
-    Matrix T_;                                    //!< The transmissibilities such that f_i = T_ij*T_j
-    Vector Tj_;                                   //!< The interaction volume-wide temperatures
-    std::vector< std::vector<Vector> > outsideT_; //!< The transmissibilities for "outside" faces (only necessary on surface grids)
+    TMatrix T_;                                       //!< The transmissibilities such that f_i = T_ij*T_j
+    CellVector Tj_;                                   //!< The interaction volume-wide temperatures
+    std::vector< std::vector<CellVector> > outsideT_; //!< The transmissibilities for "outside" faces (only necessary on surface grids)
 };
 
 //! Process-dependent data handles when related process is disabled
-template<class TypeTag, class M, class V, class LI>
-class AdvectionDataHandle<TypeTag, M, V, LI, false> : public EmptyDataHandle {};
-template<class TypeTag, class M, class V, class LI>
-class DiffusionDataHandle<TypeTag, M, V, LI, false> : public EmptyDataHandle {};
-template<class TypeTag, class M, class V, class LI>
-class HeatConductionDataHandle<TypeTag, M, V, LI, false> : public EmptyDataHandle {};
+template<class MatVecTraits, class PhysicsTraits>
+class AdvectionDataHandle<MatVecTraits, PhysicsTraits, false> : public EmptyDataHandle {};
+template<class MatVecTraits, class PhysicsTraits>
+class DiffusionDataHandle<MatVecTraits, PhysicsTraits, false> : public EmptyDataHandle {};
+template<class MatVecTraits, class PhysicsTraits>
+class HeatConductionDataHandle<MatVecTraits, PhysicsTraits, false> : public EmptyDataHandle {};
 
 /*!
  * \ingroup CCMpfaDiscretization
  * \brief Class for the interaction volume data handle.
  *
- * \tparam TypeTag The problem TypeTag
- * \tparam M The type used for iv-local matrices
- * \tparam V The type used for iv-local vectors
- * \tparam LI The type used for iv-local indexing
+ * \tparam MVT The matrix/vector traits collecting type information used by the iv
+ * \tparam PT The physics traits collecting data on the physical processes to be considered
  */
-template<class TypeTag, class M, class V, class LI>
-class InteractionVolumeDataHandle : public AdvectionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableAdvection)>,
-                                    public DiffusionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion)>,
-                                    public HeatConductionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableEnergyBalance)>
+template<class MVT, class PT>
+class InteractionVolumeDataHandle : public AdvectionDataHandle<MVT, PT, PT::enableAdvection>,
+                                    public DiffusionDataHandle<MVT, PT, PT::enableMolecularDiffusion>,
+                                    public HeatConductionDataHandle<MVT, PT, PT::enableHeatConduction>
 {
-    using AdvectionHandle = AdvectionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableAdvection)>;
-    using DiffusionHandle = DiffusionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion)>;
-    using HeatConductionHandle = HeatConductionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableEnergyBalance)>;
+    using AdvectionHandle = AdvectionDataHandle<MVT, PT, PT::enableAdvection>;
+    using DiffusionHandle = DiffusionDataHandle<MVT, PT, PT::enableMolecularDiffusion>;
+    using HeatConductionHandle = HeatConductionDataHandle<MVT, PT, PT::enableHeatConduction>;
 
 public:
     //! prepare data handles for subsequent fills
diff --git a/dumux/discretization/cellcentered/mpfa/localassembler.hh b/dumux/discretization/cellcentered/mpfa/localassembler.hh
index d5eb6bf8289f43f07a475a4cf63aaf24546e5b77..ad06867aee3fb0c3b0c2ca9b89eb32e9ad6e3e91 100644
--- a/dumux/discretization/cellcentered/mpfa/localassembler.hh
+++ b/dumux/discretization/cellcentered/mpfa/localassembler.hh
@@ -33,11 +33,11 @@
 namespace Dumux
 {
 //! Forward declaration of the implementation
-template< class IVTraits, MpfaMethods M > class InteractionVolumeAssemblerImpl;
+template< class P, class EG, class EV, MpfaMethods M > class InteractionVolumeAssemblerImpl;
 
 //! Alias to select the right implementation.
-template< class IVTraits, MpfaMethods M >
-using InteractionVolumeAssembler = InteractionVolumeAssemblerImpl< IVTraits, M >;
+template< class P, class EG, class EV, MpfaMethods M >
+using InteractionVolumeAssembler = InteractionVolumeAssemblerImpl< P, EG, EV, M >;
 
 /*!
  * \ingroup CCMpfaDiscretization
@@ -47,17 +47,16 @@ using InteractionVolumeAssembler = InteractionVolumeAssemblerImpl< IVTraits, M >
  *        for the available interaction volume implementations. these
  *        should derive from this base clases.
  *
- * \tparam IVTraits The Traits class used by the interaction volume
+ * \tparam P The problem type
+ * \tparam EG The element finite volume geometry
+ * \tparam EV The element volume variables type
  */
-template< class IVTraits >
+template< class P, class EG, class EV >
 class InteractionVolumeAssemblerBase
 {
-    using Matrix = typename IVTraits::Matrix;
-    using Vector = typename IVTraits::Vector;
-
-    using Problem = typename IVTraits::Problem;
-    using FVElementGeometry = typename IVTraits::FVElementGeometry;
-    using ElementVolumeVariables = typename IVTraits::ElementVolumeVariables;
+    using Problem = P;
+    using FVElementGeometry = EG;
+    using ElementVolumeVariables = EV;
 
   public:
     /*!
@@ -87,15 +86,15 @@ class InteractionVolumeAssemblerBase
      *        interaction volume-local transmissibility matrix.
      *
      * \tparam IV Interaction volume type implementation
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param T The transmissibility matrix to be assembled
      * \param iv The interaction volume
-     * \param getTensor Lambda to evaluate the scv-wise tensors
+     * \param getT Lambda to evaluate the scv-wise tensors
      */
-    template< class IV, class GetTensor >
-    void assemble(Matrix& T, IV& iv, const GetTensor& getTensor)
+    template< class IV, class TensorFunc >
+    void assemble(typename IV::Traits::MatVecTraits::MatVecTraits::TMatrix& T, IV& iv, const TensorFunc& getT)
     {
         DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assemble() function");
     }
@@ -108,16 +107,16 @@ class InteractionVolumeAssemblerBase
      *
      * \tparam TOutside Container to store the "outside" transmissibilities
      * \tparam IV Interaction volume type implementation
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param outsideTij tij on "outside" faces to be assembled
      * \param T The transmissibility matrix tij to be assembled
      * \param iv The mpfa-o interaction volume
-     * \param getTensor Lambda to evaluate the scv-wise tensors
+     * \param getT Lambda to evaluate the scv-wise tensors
      */
-    template< class TOutside, class IV, class GetTensor >
-    void assemble(TOutside& outsideTij, Matrix& T, IV& iv, const GetTensor& getTensor)
+    template< class TOutside, class IV, class TensorFunc >
+    void assemble(TOutside& outsideTij, typename IV::Traits::MatVecTraits::TMatrix& T, IV& iv, const TensorFunc& getT)
     {
         DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assemble() function to be used on surface grids");
     }
@@ -130,17 +129,21 @@ class InteractionVolumeAssemblerBase
      * \tparam GC The type of container used to store the
      *            gravitational acceleration per scvf & phase
      * \tparam IV The interaction volume type implementation
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param T The transmissibility matrix to be assembled
      * \param g Container to assemble gravity per scvf & phase
      * \param CA Matrix to store matrix product C*A^-1
      * \param iv The interaction volume
-     * \param getTensor Lambda to evaluate the scv-wise tensors
+     * \param getT Lambda to evaluate the scv-wise tensors
      */
-    template< class GC, class IV, class GetTensor >
-    void assembleWithGravity(Matrix& T, GC& g, Matrix& CA, IV& iv, const GetTensor& getTensor)
+    template< class GC, class IV, class TensorFunc >
+    void assembleWithGravity(typename IV::Traits::MatVecTraits::TMatrix& T,
+                             GC& g,
+                             typename IV::Traits::MatVecTraits::CMatrix& CA,
+                             IV& iv,
+                             const TensorFunc& getT)
     {
         DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assembleWithGravity() function");
     }
@@ -158,8 +161,8 @@ class InteractionVolumeAssemblerBase
      * \tparam GOut Type of container used to store gravity on "outside" faces
      * \tparam TOutside Container to store the "outside" transmissibilities
      * \tparam IV The interaction volume type implementation
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param outsideTij tij on "outside" faces to be assembled
      * \param T The transmissibility matrix to be assembled
@@ -168,17 +171,17 @@ class InteractionVolumeAssemblerBase
      * \param CA Matrix to store matrix product C*A^-1
      * \param A Matrix to store the inverse A^-1
      * \param iv The interaction volume
-     * \param getTensor Lambda to evaluate the scv-wise tensors
+     * \param getT Lambda to evaluate the scv-wise tensors
      */
-    template< class GC, class GOut, class TOutside, class IV, class GetTensor >
+    template< class GC, class GOut, class TOutside, class IV, class TensorFunc >
     void assembleWithGravity(TOutside& outsideTij,
-                             Matrix& T,
+                             typename IV::Traits::MatVecTraits::TMatrix& T,
                              GOut& outsideG,
                              GC& g,
-                             Matrix& CA,
-                             Matrix& A,
+                             typename IV::Traits::MatVecTraits::CMatrix& CA,
+                             typename IV::Traits::MatVecTraits::AMatrix& A,
                              IV& iv,
-                             const GetTensor& getTensor)
+                             const TensorFunc& getT)
     {
         DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assembleWithGravity() function to be used on surface grids");
     }
@@ -196,7 +199,7 @@ class InteractionVolumeAssemblerBase
      * \param getU Lambda to obtain the desired cell value from grid indices
      */
     template< class IV, class GetU >
-    void assemble(Vector& u, const IV& iv, const GetU& getU)
+    void assemble(typename IV::Traits::MatVecTraits::CellVector& u, const IV& iv, const GetU& getU)
     {
         DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assemble() function for the cell unknowns");
     }
@@ -211,17 +214,17 @@ class InteractionVolumeAssemblerBase
      *
      * \tparam GC The type of container used to store the
      *            gravitational acceleration per scvf & phase
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param g Container to assemble gravity per scvf & phase
      * \param iv The interaction volume
      * \param CA Projection matrix transforming the gravity terms in the local system of
      *        equations to the entire set of faces within the interaction volume
-     * \param getTensor Lambda to evaluate scv-wise hydraulic conductivities
+     * \param getT Lambda to evaluate scv-wise hydraulic conductivities
      */
-    template< class GC, class IV, class GetTensor >
-    void assembleGravity(GC& g, const IV& iv, const Matrix& CA, const GetTensor& getTensor)
+    template< class GC, class IV, class TensorFunc >
+    void assembleGravity(GC& g, const IV& iv, const typename IV::Traits::MatVecTraits::CMatrix& CA, const TensorFunc& getT)
     {
         DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assembleGravity() function");
     }
@@ -240,8 +243,8 @@ class InteractionVolumeAssemblerBase
      *            gravitational acceleration per scvf & phase
      * \tparam GOut Type of container used to store gravity on "outside" faces
      * \tparam IV The interaction volume type implementation
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param g Container to store gravity per scvf & phase
      * \param outsideG Container to store gravity per "outside" scvf & phase
@@ -249,15 +252,15 @@ class InteractionVolumeAssemblerBase
      * \param CA Projection matrix transforming the gravity terms in the local system of
      *        equations to the entire set of faces within the interaction volume
      * \param A Matrix needed for the "reconstruction" of face unknowns as a function of gravity
-     * \param getTensor Lambda to evaluate scv-wise hydraulic conductivities
+     * \param getT Lambda to evaluate scv-wise hydraulic conductivities
      */
-    template< class GC, class GOut, class IV, class GetTensor >
+    template< class GC, class GOut, class IV, class TensorFunc >
     void assembleGravity(GC& g,
                          GOut& outsideG,
                          const IV& iv,
-                         const Matrix& CA,
-                         const Matrix& A,
-                         const GetTensor& getTensor)
+                         const typename IV::Traits::MatVecTraits::CMatrix& CA,
+                         const typename IV::Traits::MatVecTraits::AMatrix& A,
+                         const TensorFunc& getT)
     {
         DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assembleGravity() function to be used on surface grids");
     }
diff --git a/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh b/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh
index 4629683fd96bf1c6e99e391cc92df4dd543bed6a..534291070f5c649bdd99b5dbeff4e25d4579c7e6 100644
--- a/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh
+++ b/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh
@@ -24,12 +24,14 @@
 #ifndef DUMUX_DISCRETIZATION_CC_MPFA_O_INTERACTIONVOLUME_HH
 #define DUMUX_DISCRETIZATION_CC_MPFA_O_INTERACTIONVOLUME_HH
 
+#include <type_traits>
+
 #include <dune/common/dynmatrix.hh>
 #include <dune/common/dynvector.hh>
 #include <dune/common/fvector.hh>
+#include <dune/common/reservedvector.hh>
 
 #include <dumux/common/math.hh>
-#include <dumux/common/properties.hh>
 #include <dumux/common/matrixvectorhelper.hh>
 
 #include <dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh>
@@ -46,31 +48,44 @@ namespace Dumux
 //! Forward declaration of the o-method's interaction volume
 template< class Traits > class CCMpfaOInteractionVolume;
 
-//! Specialization of the default interaction volume traits class for the mpfa-o method
-template< class TypeTag >
+/*!
+ * \ingroup CCMpfaDiscretization
+ * \brief The default interaction volume traits class for the mpfa-o method.
+ *        This uses dynamic types types for matrices/vectors in order to work
+ *        on general grids. For interaction volumes known at compile time use
+ *        the static interaction volume implementation.
+ *
+ * \tparam NodalIndexSet The type used for the dual grid's nodal index sets
+ * \tparam Scalar The Type used for scalar values
+ * \tparam PhysicsTraits Traits class encapsulating info on the physical processes
+ */
+template< class NodalIndexSet, class Scalar, class PhysicsTraits >
 struct CCMpfaODefaultInteractionVolumeTraits
 {
 private:
-    using NodalIndexSet = typename GET_PROP_TYPE(TypeTag, DualGridNodalIndexSet);
     using GridIndexType = typename NodalIndexSet::GridIndexType;
-    static constexpr int dim = GET_PROP_TYPE(TypeTag, GridView)::dimension;
-    static constexpr int dimWorld = GET_PROP_TYPE(TypeTag, GridView)::dimensionworld;
+    using LocalIndexType = typename NodalIndexSet::LocalIndexType;
+
+    static constexpr int dim = NodalIndexSet::GridView::dimension;
+    static constexpr int dimWorld = NodalIndexSet::GridView::dimensionworld;
+
+    //! Matrix/Vector traits to be used by the data handle
+    struct MVTraits
+    {
+        using AMatrix = Dune::DynamicMatrix< Scalar >;
+        using BMatrix = Dune::DynamicMatrix< Scalar >;
+        using CMatrix = Dune::DynamicMatrix< Scalar >;
+        using DMatrix = Dune::DynamicMatrix< Scalar >;
+        using TMatrix = Dune::DynamicMatrix< Scalar >;
+        using CellVector = Dune::DynamicVector< Scalar >;
+        using FaceVector = Dune::DynamicVector< Scalar >;
+    };
 
 public:
-    //! export the problem type (needed for iv-local assembly)
-    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
-    //! export the type of the local view on the finite volume grid geometry
-    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView;
-    //! export the type of the local view on the grid volume variables
-    using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
     //! export the type of grid view
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+    using GridView = typename NodalIndexSet::GridView;
     //! export the type used for scalar values
-    using ScalarType = typename GET_PROP_TYPE(TypeTag, Scalar);
-    //! export the type of the mpfa helper class
-    using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper);
-    //! export the type used for local indices
-    using LocalIndexType = typename NodalIndexSet::LocalIndexType;
+    using ScalarType = Scalar;
     //! export the type for the interaction volume index set
     using IndexSet = CCMpfaOInteractionVolumeIndexSet< NodalIndexSet >;
     //! export the type of interaction-volume local scvs
@@ -79,12 +94,10 @@ public:
     using LocalScvfType = CCMpfaOInteractionVolumeLocalScvf< IndexSet >;
     //! export the type of used for the iv-local face data
     using LocalFaceData = InteractionVolumeLocalFaceData<GridIndexType, LocalIndexType>;
-    //! export the type used for iv-local matrices
-    using Matrix = Dune::DynamicMatrix< ScalarType >;
-    //! export the type used for iv-local vectors
-    using Vector = Dune::DynamicVector< ScalarType >;
+    //! export the matrix/vector traits to be used by the iv
+    using MatVecTraits = MVTraits;
     //! export the data handle type for this iv
-    using DataHandle = InteractionVolumeDataHandle< TypeTag, Matrix, Vector, LocalIndexType >;
+    using DataHandle = InteractionVolumeDataHandle< MatVecTraits, PhysicsTraits >;
 };
 
 /*!
@@ -94,38 +107,38 @@ public:
  *        and can be used at boundaries and on unstructured grids.
  */
 template< class Traits >
-class CCMpfaOInteractionVolume : public CCMpfaInteractionVolumeBase< CCMpfaOInteractionVolume<Traits>, Traits >
+class CCMpfaOInteractionVolume
+      : public CCMpfaInteractionVolumeBase< CCMpfaOInteractionVolume<Traits>, Traits >
 {
-    using ThisType = CCMpfaOInteractionVolume< Traits >;
-    using ParentType = CCMpfaInteractionVolumeBase< CCMpfaOInteractionVolume<Traits>, Traits >;
-
-    using Scalar = typename Traits::ScalarType;
-    using Helper = typename Traits::MpfaHelper;
-    using Problem = typename Traits::Problem;
-    using FVElementGeometry = typename Traits::FVElementGeometry;
-
     using GridView = typename Traits::GridView;
     using Element = typename GridView::template Codim<0>::Entity;
 
+    using IndexSet = typename Traits::IndexSet;
+    using GridIndexType = typename IndexSet::GridIndexType;
+    using LocalIndexType = typename IndexSet::LocalIndexType;
+    using Stencil = typename IndexSet::GridStencilType;
+
     static constexpr int dim = GridView::dimension;
-    using DimVector = Dune::FieldVector<Scalar, dim>;
+    static constexpr int dimWorld = GridView::dimensionworld;
+    using DimVector = Dune::FieldVector<typename Traits::ScalarType, dim>;
+    using FaceOmegas = typename std::conditional< (dim<dimWorld),
+                                                  std::vector<DimVector>,
+                                                  Dune::ReservedVector<DimVector, 2> >::type;
+
+    using AMatrix = typename Traits::MatVecTraits::AMatrix;
+    using BMatrix = typename Traits::MatVecTraits::BMatrix;
+    using CMatrix = typename Traits::MatVecTraits::CMatrix;
 
-    using Matrix = typename Traits::Matrix;
     using LocalScvType = typename Traits::LocalScvType;
     using LocalScvfType = typename Traits::LocalScvfType;
     using LocalFaceData = typename Traits::LocalFaceData;
 
-    using IndexSet = typename Traits::IndexSet;
-    using GridIndexType = typename GridView::IndexSet::IndexType;
-    using LocalIndexType = typename Traits::LocalIndexType;
-    using Stencil = typename IndexSet::GridStencilType;
-
+public:
     //! Data attached to scvf touching Dirichlet boundaries.
     //! For the default o-scheme, we only store the corresponding vol vars index.
     class DirichletData
     {
         GridIndexType volVarIndex_;
-
     public:
         //! Constructor
         DirichletData(const GridIndexType index) : volVarIndex_(index) {}
@@ -134,11 +147,14 @@ class CCMpfaOInteractionVolume : public CCMpfaInteractionVolumeBase< CCMpfaOInte
         GridIndexType volVarIndex() const { return volVarIndex_; }
     };
 
-public:
+    //! export the type used for transmissibility storage
+    using TransmissibilityStorage = std::vector< FaceOmegas >;
+
     //! publicly state the mpfa-scheme this interaction volume is associated with
     static constexpr MpfaMethods MpfaMethod = MpfaMethods::oMethod;
 
     //! Sets up the local scope for a given iv index set
+    template< class Problem, class FVElementGeometry >
     void setUpLocalScope(const IndexSet& indexSet,
                          const Problem& problem,
                          const FVElementGeometry& fvGeometry)
@@ -147,7 +163,7 @@ public:
         // index set of the dual grid's nodal index set
         stencil_ = &indexSet.nodalIndexSet().globalScvIndices();
 
-        // number of interaction-volume-local (= node-local for o-scheme) scvs/scvf
+        // number of interaction-volume-local scvs(=node-local for o-scheme) and scvfs
         numFaces_ = indexSet.numFaces();
         const auto numLocalScvs = indexSet.numScvs();
         const auto numGlobalScvfs = indexSet.nodalIndexSet().numScvfs();
@@ -164,29 +180,26 @@ public:
         dirichletData_.reserve(numFaces_);
         localFaceData_.reserve(numGlobalScvfs);
 
-        // set up quantities related to sub-control volumes
+        // set up stuff related to sub-control volumes
         const auto& scvIndices = indexSet.globalScvIndices();
         for (LocalIndexType scvIdxLocal = 0; scvIdxLocal < numLocalScvs; scvIdxLocal++)
         {
-            scvs_.emplace_back(Helper(),
+            elements_.emplace_back(fvGeometry.fvGridGeometry().element( scvIndices[scvIdxLocal] ));
+            scvs_.emplace_back(fvGeometry.fvGridGeometry().mpfaHelper(),
                                fvGeometry,
                                fvGeometry.scv( scvIndices[scvIdxLocal] ),
                                scvIdxLocal,
                                indexSet);
-            elements_.emplace_back(fvGeometry.fvGridGeometry().element( scvIndices[scvIdxLocal] ));
         }
 
         // keep track of the number of unknowns etc
         numUnknowns_ = 0;
         numKnowns_ = numLocalScvs;
 
-        // resize omega storage container
-        wijk_.resize(numFaces_);
-
         // set up quantitites related to sub-control volume faces
+        wijk_.resize(numFaces_);
         for (LocalIndexType faceIdxLocal = 0; faceIdxLocal < numFaces_; ++faceIdxLocal)
         {
-            // get corresponding grid scvf
             const auto& scvf = fvGeometry.scvf(indexSet.scvfIdxGlobal(faceIdxLocal));
 
             // the neighboring scvs in local indices (order: 0 - inside scv, 1..n - outside scvs)
@@ -195,6 +208,10 @@ public:
             // create local face data object for this face
             localFaceData_.emplace_back(faceIdxLocal, neighborScvIndicesLocal[0], scvf.index());
 
+            // we will need as many omegas as scvs around the face
+            const auto numNeighborScvs = neighborScvIndicesLocal.size();
+            wijk_[faceIdxLocal].resize(numNeighborScvs);
+
             // create iv-local scvf object
             if (scvf.boundary())
             {
@@ -207,18 +224,11 @@ public:
                 }
                 else
                     scvfs_.emplace_back(scvf, neighborScvIndicesLocal, numUnknowns_++, /*isDirichlet*/false);
-
-                // on boundary faces we will only need one inside omega
-                wijk_[faceIdxLocal].resize(1);
             }
             else
             {
                 scvfs_.emplace_back(scvf, neighborScvIndicesLocal, numUnknowns_++, /*isDirichlet*/false);
 
-                // we will need as many omegas as scvs around the face
-                const auto numNeighborScvs = neighborScvIndicesLocal.size();
-                wijk_[faceIdxLocal].resize(numNeighborScvs);
-
                 // add local face data objects for the outside faces
                 for (LocalIndexType i = 1; i < numNeighborScvs; ++i)
                 {
@@ -234,8 +244,12 @@ public:
                                                         outsideLocalScvIdx, // iv-local scv index
                                                         i-1,                // scvf-local index in outside faces
                                                         flipScvf.index());  // global scvf index
+                            break; // go to next outside face
                         }
                     }
+
+                    // make sure we found it
+                    assert(localFaceData_.back().ivLocalInsideScvIndex() == outsideLocalScvIdx);
                 }
             }
         }
@@ -262,13 +276,13 @@ public:
     const Stencil& stencil() const { return *stencil_; }
 
     //! returns the grid element corresponding to a given iv-local scv idx
-    const Element& element(const LocalIndexType ivLocalScvIdx) const { return elements_[ivLocalScvIdx]; }
+    const Element& element(LocalIndexType ivLocalScvIdx) const { return elements_[ivLocalScvIdx]; }
 
     //! returns the local scvf entity corresponding to a given iv-local scvf idx
-    const LocalScvfType& localScvf(const LocalIndexType ivLocalScvfIdx) const { return scvfs_[ivLocalScvfIdx]; }
+    const LocalScvfType& localScvf(LocalIndexType ivLocalScvfIdx) const { return scvfs_[ivLocalScvfIdx]; }
 
     //! returns the local scv entity corresponding to a given iv-local scv idx
-    const LocalScvType& localScv(const LocalIndexType ivLocalScvIdx) const { return scvs_[ivLocalScvIdx]; }
+    const LocalScvType& localScv(LocalIndexType ivLocalScvIdx) const { return scvs_[ivLocalScvIdx]; }
 
     //! returns a reference to the container with the local face data
     const std::vector<LocalFaceData>& localFaceData() const { return localFaceData_; }
@@ -277,26 +291,24 @@ public:
     const std::vector<DirichletData>& dirichletData() const { return dirichletData_; }
 
     //! returns the matrix associated with face unknowns in local equation system
-    const Matrix& A() const { return A_; }
-    Matrix& A() { return A_; }
+    const AMatrix& A() const { return A_; }
+    AMatrix& A() { return A_; }
 
     //! returns the matrix associated with cell unknowns in local equation system
-    const Matrix& B() const { return B_; }
-    Matrix& B() { return B_; }
+    const BMatrix& B() const { return B_; }
+    BMatrix& B() { return B_; }
 
     //! returns the matrix associated with face unknowns in flux expressions
-    const Matrix& C() const { return C_; }
-    Matrix& C() { return C_; }
+    const CMatrix& C() const { return C_; }
+    CMatrix& C() { return C_; }
 
     //! returns container storing the transmissibilities for each face & coordinate
-    const std::vector< std::vector< DimVector > >& omegas() const { return wijk_; }
-    std::vector< std::vector< DimVector > >& omegas() { return wijk_; }
+    const TransmissibilityStorage& omegas() const { return wijk_; }
+    TransmissibilityStorage& omegas() { return wijk_; }
 
     //! returns the number of interaction volumes living around a vertex
-    //! the mpfa-o scheme always constructs one iv per vertex
-    template< class NodalIndexSet >
-    static constexpr std::size_t numInteractionVolumesAtVertex(const NodalIndexSet& nodalIndexSet)
-    { return 1; }
+    template< class NI >
+    static constexpr std::size_t numInteractionVolumesAtVertex(const NI& nodalIndexSet) { return 1; }
 
     //! adds the iv index sets living around a vertex to a given container
     //! and stores the the corresponding index in a map for each scvf
@@ -332,12 +344,12 @@ private:
     std::vector<DirichletData> dirichletData_;
 
     // Matrices needed for computation of transmissibilities
-    Matrix A_;
-    Matrix B_;
-    Matrix C_;
+    AMatrix A_;
+    BMatrix B_;
+    CMatrix C_;
 
     // The omega factors are stored during assembly of local system
-    std::vector< std::vector< DimVector > > wijk_;
+    TransmissibilityStorage wijk_;
 
     // sizes involved in the local system equations
     std::size_t numFaces_;
diff --git a/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh b/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh
index fd6700c7273d300f4433326e262320f653e77614..09f5eecde6e604cb663f3ac722ca05b481a0aade 100644
--- a/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh
+++ b/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh
@@ -41,20 +41,15 @@ namespace Dumux
  * \brief Specialization of the interaction volume-local
  *        assembler class for the schemes using an mpfa-o type assembly.
  *
- * \tparam IVTraits The traits class used by the interaction volume implemetation
+ * \tparam P The problem type
+ * \tparam EG The element finite volume geometry
+ * \tparam EV The element volume variables type
  */
-template< class IVTraits >
-class InteractionVolumeAssemblerImpl< IVTraits, MpfaMethods::oMethod >
-      : public InteractionVolumeAssemblerBase< IVTraits >
+template< class P, class EG, class EV >
+class InteractionVolumeAssemblerImpl< P, EG, EV, MpfaMethods::oMethod >
+      : public InteractionVolumeAssemblerBase< P, EG, EV >
 {
-    using ParentType = InteractionVolumeAssemblerBase< IVTraits >;
-
-    using LocalIndexType = typename IVTraits::LocalIndexType;
-    using Matrix = typename IVTraits::Matrix;
-    using Vector = typename IVTraits::Vector;
-
-    static constexpr int dim = IVTraits::LocalScvType::myDimension;
-    static constexpr int dimWorld = IVTraits::LocalScvType::worldDimension;
+    using ParentType = InteractionVolumeAssemblerBase< P, EG, EV >;
 
 public:
     //! Use the constructor of the base class
@@ -65,18 +60,18 @@ public:
      *        interaction volume in an mpfa-o type way.
      *
      * \tparam IV The interaction volume type implementation
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
      *                   which the local system is to be solved
      *
      * \param T The transmissibility matrix to be assembled
      * \param iv The interaction volume
-     * \param getTensor Lambda to evaluate the scv-wise tensors
+     * \param getT Lambda to evaluate the scv-wise tensors
      */
-    template< class IV, class GetTensor >
-    void assemble(Matrix& T, IV& iv, const GetTensor& getTensor)
+    template< class IV, class TensorFunc >
+    void assemble(typename IV::Traits::MatVecTraits::TMatrix& T, IV& iv, const TensorFunc& getT)
     {
         // assemble D into T directly
-        assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getTensor);
+        assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getT);
 
         // maybe solve the local system
         if (iv.numUnknowns() > 0)
@@ -95,19 +90,19 @@ public:
      *
      * \tparam TOutside Container to store the "outside" transmissibilities
      * \tparam IV The interaction volume type implementation
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param outsideTij tij on "outside" faces to be assembled
      * \param T The transmissibility matrix tij to be assembled
      * \param iv The interaction volume
-     * \param getTensor Lambda to evaluate the scv-wise tensors
+     * \param getT Lambda to evaluate the scv-wise tensors
      */
-    template< class TOutside, class IV, class GetTensor >
-    void assemble(TOutside& outsideTij, Matrix& T, IV& iv, const GetTensor& getTensor)
+    template< class TOutside, class IV, class TensorFunc >
+    void assemble(TOutside& outsideTij, typename IV::Traits::MatVecTraits::TMatrix& T, IV& iv, const TensorFunc& getT)
     {
         // assemble D into T directly
-        assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getTensor);
+        assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getT);
 
         // maybe solve the local system
         if (iv.numUnknowns() > 0)
@@ -135,7 +130,8 @@ public:
                 tij = 0.0;
 
                 // add contributions from all local directions
-                for (LocalIndexType localDir = 0; localDir < dim; localDir++)
+                using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType;
+                for (LocalIndexType localDir = 0; localDir < IV::Traits::GridView::dimension; localDir++)
                 {
                     // the scvf corresponding to this local direction in the scv
                     const auto& curLocalScvf = iv.localScvf(posLocalScv.scvfIdxLocal(localDir));
@@ -166,20 +162,24 @@ public:
      * \tparam GC The type of container used to store the
      *            gravitational acceleration per scvf & phase
      * \tparam IV The interaction volume type implementation
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param T The transmissibility matrix to be assembled
      * \param g Container to assemble gravity per scvf & phase
      * \param CA Matrix to store matrix product C*A^-1
      * \param iv The mpfa-o interaction volume
-     * \param getTensor Lambda to evaluate the scv-wise tensors
+     * \param getT Lambda to evaluate the scv-wise tensors
      */
-    template< class GC, class IV, class GetTensor >
-    void assembleWithGravity(Matrix& T, GC& g, Matrix& CA, IV& iv, const GetTensor& getTensor)
+    template< class GC, class IV, class TensorFunc >
+    void assembleWithGravity(typename IV::Traits::MatVecTraits::TMatrix& T,
+                             GC& g,
+                             typename IV::Traits::MatVecTraits::CMatrix& CA,
+                             IV& iv,
+                             const TensorFunc& getT)
     {
         // assemble D into T & C into CA directly
-        assembleLocalMatrices_(iv.A(), iv.B(), CA, T, iv, getTensor);
+        assembleLocalMatrices_(iv.A(), iv.B(), CA, T, iv, getT);
 
         // maybe solve the local system
         if (iv.numUnknowns() > 0)
@@ -191,7 +191,7 @@ public:
         }
 
         // assemble gravitational acceleration container (enforce usage of mpfa-o type version)
-        assembleGravity(g, iv, CA, getTensor);
+        assembleGravity(g, iv, CA, getT);
     }
 
     /*!
@@ -206,8 +206,8 @@ public:
      * \tparam GOut Type of container used to store gravity on "outside" faces
      * \tparam TOutside Container to store the "outside" transmissibilities
      * \tparam IV The interaction volume type implementation
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param outsideTij tij on "outside" faces to be assembled
      * \param T The transmissibility matrix to be assembled
@@ -216,20 +216,20 @@ public:
      * \param CA Matrix to store matrix product C*A^-1
      * \param A Matrix to store the inverse A^-1
      * \param iv The mpfa-o interaction volume
-     * \param getTensor Lambda to evaluate the scv-wise tensors
+     * \param getT Lambda to evaluate the scv-wise tensors
      */
-    template< class GC, class GOut, class TOutside, class IV, class GetTensor >
+    template< class GC, class GOut, class TOutside, class IV, class TensorFunc >
     void assembleWithGravity(TOutside& outsideTij,
-                             Matrix& T,
+                             typename IV::Traits::MatVecTraits::TMatrix& T,
                              GOut& outsideG,
                              GC& g,
-                             Matrix& CA,
-                             Matrix& A,
+                             typename IV::Traits::MatVecTraits::CMatrix& CA,
+                             typename IV::Traits::MatVecTraits::AMatrix& A,
                              IV& iv,
-                             const GetTensor& getTensor)
+                             const TensorFunc& getT)
     {
         // assemble D into T directly
-        assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getTensor);
+        assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getT);
 
         // maybe solve the local system
         if (iv.numUnknowns() > 0)
@@ -259,7 +259,8 @@ public:
                 tij = 0.0;
 
                 // add contributions from all local directions
-                for (LocalIndexType localDir = 0; localDir < dim; localDir++)
+                using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType;
+                for (LocalIndexType localDir = 0; localDir < IV::Traits::GridView::dimension; localDir++)
                 {
                     // the scvf corresponding to this local direction in the scv
                     const auto& curLocalScvf = iv.localScvf(posLocalScv.scvfIdxLocal(localDir));
@@ -280,7 +281,7 @@ public:
             }
         }
 
-        assembleGravity(g, outsideG, iv, CA, A, getTensor);
+        assembleGravity(g, outsideG, iv, CA, A, getT);
     }
 
     /*!
@@ -295,14 +296,15 @@ public:
      * \param getU Lambda to obtain the desired cell/Dirichlet value from grid index
      */
     template< class IV, class GetU >
-    void assemble(Vector& u, const IV& iv, const GetU& getU)
+    void assemble(typename IV::Traits::MatVecTraits::CellVector& u, const IV& iv, const GetU& getU)
     {
         // put the cell pressures first
+        using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType;
         for (LocalIndexType i = 0; i < iv.numScvs(); ++i)
             u[i] = getU( iv.localScv(i).globalScvIndex() );
 
         // Dirichlet BCs come afterwards
-        unsigned int i = iv.numScvs();
+        LocalIndexType i = iv.numScvs();
         for (const auto& data : iv.dirichletData())
             u[i++] = getU( data.volVarIndex() );
     }
@@ -317,37 +319,40 @@ public:
      *
      * \tparam GC The type of container used to store the
      *            gravitational acceleration per scvf & phase
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param g Container to assemble gravity per scvf & phase
      * \param iv The mpfa-o interaction volume
      * \param CA Projection matrix transforming the gravity terms in the local system of
      *        equations to the entire set of faces within the interaction volume
-     * \param getTensor Lambda to evaluate scv-wise hydraulic conductivities
+     * \param getT Lambda to evaluate scv-wise hydraulic conductivities
      */
-    template< class GC, class IV, class GetTensor >
-    void assembleGravity(GC& g, const IV& iv, const Matrix& CA, const GetTensor& getTensor)
+    template< class GC, class IV, class TensorFunc >
+    void assembleGravity(GC& g,
+                         const IV& iv,
+                         const typename IV::Traits::MatVecTraits::CMatrix& CA,
+                         const TensorFunc& getT)
     {
         //! We require the gravity container to be a two-dimensional vector/array type, structured as follows:
         //! - first index adresses the respective phases
         //! - second index adresses the face within the interaction volume
 
-        // make sure CA matrix and the g vector to have the correct size already
-        assert(std::all_of(g.begin(), g.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); })
-               && "size of gravity vector does not match the number of iv-local faces!");
-        assert(CA.rows() == iv.numFaces() && CA.cols() == iv.numUnknowns() && "Matrix CA does not have the correct size");
+        // make sure g vector and CA matrix have the correct sizes already
+        assert(std::all_of(g.begin(), g.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); }));
+        assert(CA.rows() == iv.numFaces() && CA.cols() == iv.numUnknowns());
 
         //! For each face, we...
         //! - arithmetically average the phase densities
         //! - compute the term \f$ \alpha := A \rho \ \mathbf{n}^T \mathbf{K} \mathbf{g} \f$ in each neighboring cell
         //! - compute \f$ \alpha^* = \alpha_{outside} - \alpha_{inside} \f$
-        using Scalar = typename Vector::value_type;
+        using Scalar = typename IV::Traits::ScalarType;
+        using FaceVector = typename IV::Traits::MatVecTraits::FaceVector;
+        using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType;
 
         // reset gravity containers to zero
         const auto numPhases = g.size();
-        std::vector< Vector > sum_alphas(numPhases);
-
+        std::vector< FaceVector > sum_alphas(numPhases);
         for (unsigned int pIdx = 0; pIdx < numPhases; ++pIdx)
         {
             resizeVector(sum_alphas[pIdx], iv.numUnknowns());
@@ -368,11 +373,10 @@ public:
             const auto& posGlobalScv = this->fvGeometry().scv(posLocalScv.globalScvIndex());
             const auto& posVolVars = this->elemVolVars()[posGlobalScv];
             const auto& posElement = iv.element(neighborScvIndices[0]);
-            const auto tensor = getTensor(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv);
+            const auto tensor = getT(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv);
 
-            // This function should never be called for surface grids,
-            // for which there is the specialization of this function below
-            assert(neighborScvIndices.size() <= 2 && "Scvf seems to have more than one outside scv!");
+            // On surface grids one should use the function specialization below
+            assert(neighborScvIndices.size() <= 2);
 
             std::vector< Scalar > rho(numPhases);
             const auto alpha_inside = posVolVars.extrusionFactor()*vtmv(curGlobalScvf.unitOuterNormal(), tensor, gravity);
@@ -388,7 +392,7 @@ public:
                     const auto& negGlobalScv = this->fvGeometry().scv(negLocalScv.globalScvIndex());
                     const auto& negVolVars = this->elemVolVars()[negGlobalScv];
                     const auto& negElement = iv.element( neighborScvIndices[1] );
-                    const auto negTensor = getTensor(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv);
+                    const auto negTensor = getT(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv);
 
                     const auto sum_alpha = negVolVars.extrusionFactor()
                                            * vtmv(curGlobalScvf.unitOuterNormal(), negTensor, gravity)
@@ -439,8 +443,8 @@ public:
      *            gravitational acceleration per scvf & phase
      * \tparam GOut Type of container used to store gravity on "outside" faces
      * \tparam IV The interaction volume type implementation
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param g Container to store gravity per scvf & phase
      * \param outsideG Container to store gravity per "outside" scvf & phase
@@ -448,15 +452,15 @@ public:
      * \param CA Projection matrix transforming the gravity terms in the local system of
      *        equations to the entire set of faces within the interaction volume
      * \param A Matrix needed for the "reconstruction" of face unknowns as a function of gravity
-     * \param getTensor Lambda to evaluate scv-wise hydraulic conductivities
+     * \param getT Lambda to evaluate scv-wise hydraulic conductivities
      */
-    template< class GC, class GOut, class IV, class GetTensor >
+    template< class GC, class GOut, class IV, class TensorFunc >
     void assembleGravity(GC& g,
                          GOut& outsideG,
                          const IV& iv,
-                         const Matrix& CA,
-                         const Matrix& A,
-                         const GetTensor& getTensor)
+                         const typename IV::Traits::MatVecTraits::CMatrix& CA,
+                         const typename IV::Traits::MatVecTraits::AMatrix& A,
+                         const TensorFunc& getT)
     {
         //! We require the gravity container to be a two-dimensional vector/array type, structured as follows:
         //! - first index adresses the respective phases
@@ -467,22 +471,21 @@ public:
         //! - third index adresses the i-th "outside" face of the current face
 
         // we require the CA matrix and the gravity containers to have the correct size already
-        assert(CA.rows() == iv.numFaces() && CA.cols() == iv.numUnknowns() && "Matrix CA does not have the correct size");
-        assert(std::all_of(g.begin(), g.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); })
-               && "size of gravity container does not match the number of iv-local faces!");
-        assert(std::all_of(outsideG.begin(), outsideG.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); })
-               && "Outside gravity container does not match the number of iv-local faces!");
+        assert(CA.rows() == iv.numFaces() && CA.cols() == iv.numUnknowns());
+        assert(std::all_of(g.begin(), g.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); }));
+        assert(std::all_of(outsideG.begin(), outsideG.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); }));
 
         //! For each face, we...
         //! - arithmetically average the phase densities
         //! - compute the term \f$ \alpha := \mathbf{A} \rho \ \mathbf{n}^T \mathbf{K} \mathbf{g} \f$ in each neighboring cell
         //! - compute \f$ \alpha^* = \sum{\alpha_{outside, i}} - \alpha_{inside} \f$
-        using Scalar = typename Vector::value_type;
+        using Scalar = typename IV::Traits::ScalarType;
+        using FaceVector = typename IV::Traits::MatVecTraits::FaceVector;
+        using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType;
 
         // reset everything to zero
         const auto numPhases = g.size();
-        std::vector< Vector > sum_alphas(numPhases);
-
+        std::vector< FaceVector > sum_alphas(numPhases);
         for (unsigned int pIdx = 0; pIdx < numPhases; ++pIdx)
         {
             resizeVector(sum_alphas[pIdx], iv.numUnknowns());
@@ -504,7 +507,7 @@ public:
             const auto& posGlobalScv = this->fvGeometry().scv(posLocalScv.globalScvIndex());
             const auto& posVolVars = this->elemVolVars()[posGlobalScv];
             const auto& posElement = iv.element(neighborScvIndices[0]);
-            const auto tensor = getTensor(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv);
+            const auto tensor = getT(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv);
 
             const auto alpha_inside = posVolVars.extrusionFactor()*vtmv(curGlobalScvf.unitOuterNormal(), tensor, gravity);
             const auto numOutsideFaces = curGlobalScvf.boundary() ? 0 : curGlobalScvf.numOutsideScvs();
@@ -527,11 +530,10 @@ public:
                         const auto& negGlobalScv = this->fvGeometry().scv(negLocalScv.globalScvIndex());
                         const auto& negVolVars = this->elemVolVars()[negGlobalScv];
                         const auto& negElement = iv.element( neighborScvIndices[idxInOutside] );
-                        const auto negTensor = getTensor(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv);
+                        const auto negTensor = getT(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv);
 
                         const auto& flipScvf = this->fvGeometry().flipScvf(curGlobalScvf.index(), idxInOutside);
-                        alpha_outside[idxInOutside] = negVolVars.extrusionFactor()
-                                                      * vtmv(flipScvf.unitOuterNormal(), negTensor, gravity);
+                        alpha_outside[idxInOutside] = negVolVars.extrusionFactor()*vtmv(flipScvf.unitOuterNormal(), negTensor, gravity);
 
                         for (unsigned int pIdx = 0; pIdx < numPhases; ++pIdx)
                         {
@@ -572,7 +574,7 @@ public:
         {
             CA.umv(sum_alphas[pIdx], g[pIdx]);
 
-            Vector AG(iv.numUnknowns());
+            FaceVector AG(iv.numUnknowns());
             A.mv(sum_alphas[pIdx], AG);
 
             // compute gravitational accelerations
@@ -588,8 +590,11 @@ public:
                 const auto& posLocalScv = iv.localScv(localScvIdx);
                 const auto& wijk = iv.omegas()[localScvfIdx][idxInOutside+1];
 
+                // make sure the given outside gravity container has the right size
+                assert(outsideG[pIdx][localScvfIdx].size() == iv.localScvf(localScvfIdx).neighboringLocalScvIndices().size());
+
                 // add contributions from all local directions
-                for (LocalIndexType localDir = 0; localDir < dim; localDir++)
+                for (LocalIndexType localDir = 0; localDir < IV::Traits::GridView::dimension; localDir++)
                 {
                     // the scvf corresponding to this local direction in the scv
                     const auto& curLocalScvf = iv.localScvf(posLocalScv.scvfIdxLocal(localDir));
@@ -616,22 +621,29 @@ private:
      * \note  The matrices are expected to have been resized beforehand.
      *
      * \tparam IV The interaction volume type implementation
-     * \tparam GetTensor Lambda to obtain the tensor w.r.t.
-     *                   which the local system is to be solved
+     * \tparam TensorFunc Lambda to obtain the tensor w.r.t.
+     *                    which the local system is to be solved
      *
      * \param A The A matrix of the iv-local equation system
      * \param B The B matrix of the iv-local equation system
      * \param C The C matrix of the iv-local flux expressions
      * \param D The D matrix of the iv-local flux expressions
      * \param iv The mpfa-o interaction volume
-     * \param getTensor Lambda to evaluate the scv-wise tensors
+     * \param getT Lambda to evaluate the scv-wise tensors
      */
-    template< class IV, class GetTensor >
-    void assembleLocalMatrices_(Matrix& A, Matrix& B, Matrix& C, Matrix& D,
-                                IV& iv, const GetTensor& getTensor)
+    template< class IV, class TensorFunc >
+    void assembleLocalMatrices_(typename IV::Traits::MatVecTraits::AMatrix& A,
+                                typename IV::Traits::MatVecTraits::BMatrix& B,
+                                typename IV::Traits::MatVecTraits::CMatrix& C,
+                                typename IV::Traits::MatVecTraits::DMatrix& D,
+                                IV& iv, const TensorFunc& getT)
     {
+        using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType;
+        static constexpr int dim = IV::Traits::GridView::dimension;
+        static constexpr int dimWorld = IV::Traits::GridView::dimensionworld;
+
         // Matrix D is assumed to have the right size already
-        assert(D.rows() == iv.numFaces() && D.cols() == iv.numKnowns() && "Matrix D does not have the correct size");
+        assert(D.rows() == iv.numFaces() && D.cols() == iv.numKnowns());
 
         // if only Dirichlet faces are present in the iv,
         // the matrices A, B & C are undefined and D = T
@@ -652,7 +664,7 @@ private:
                 const auto& posGlobalScv = this->fvGeometry().scv(posLocalScv.globalScvIndex());
                 const auto& posVolVars = this->elemVolVars()[posGlobalScv];
                 const auto& posElement = iv.element(neighborScvIndices[0]);
-                const auto tensor = getTensor(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv);
+                const auto tensor = getT(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv);
 
                 // the omega factors of the "positive" sub volume
                 const auto wijk = computeMpfaTransmissibility(posLocalScv, curGlobalScvf, tensor, posVolVars.extrusionFactor());
@@ -670,9 +682,9 @@ private:
         else
         {
             // we require the matrices A,B,C to have the correct size already
-            assert(A.rows() == iv.numUnknowns() && A.cols() == iv.numUnknowns() && "Matrix A does not have the correct size");
-            assert(B.rows() == iv.numUnknowns() && B.cols() == iv.numKnowns() && "Matrix B does not have the correct size");
-            assert(C.rows() == iv.numFaces() && C.cols() == iv.numUnknowns() && "Matrix C does not have the correct size");
+            assert(A.rows() == iv.numUnknowns() && A.cols() == iv.numUnknowns());
+            assert(B.rows() == iv.numUnknowns() && B.cols() == iv.numKnowns());
+            assert(C.rows() == iv.numFaces() && C.cols() == iv.numUnknowns());
 
             // reset matrices
             A = 0.0;
@@ -694,7 +706,7 @@ private:
                 const auto& posGlobalScv = this->fvGeometry().scv(posLocalScv.globalScvIndex());
                 const auto& posVolVars = this->elemVolVars()[posGlobalScv];
                 const auto& posElement = iv.element(neighborScvIndices[0]);
-                const auto tensor = getTensor(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv);
+                const auto tensor = getT(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv);
 
                 // the omega factors of the "positive" sub volume
                 wijk[faceIdx][0] = computeMpfaTransmissibility(posLocalScv, curGlobalScvf, tensor, posVolVars.extrusionFactor());
@@ -740,7 +752,7 @@ private:
                         const auto& negGlobalScv = this->fvGeometry().scv(negLocalScv.globalScvIndex());
                         const auto& negVolVars = this->elemVolVars()[negGlobalScv];
                         const auto& negElement = iv.element( neighborScvIndices[idxOnScvf] );
-                        const auto negTensor = getTensor(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv);
+                        const auto negTensor = getT(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv);
 
                         // On surface grids, use outside face for "negative" transmissibility calculation
                         const auto& scvf = dim < dimWorld ? this->fvGeometry().flipScvf(curGlobalScvf.index(), idxInOutside)
diff --git a/dumux/discretization/cellcentered/mpfa/properties.hh b/dumux/discretization/cellcentered/mpfa/properties.hh
index 06f3d8704a822edb5cd882f1d935ea00745607e5..220f4dbe53e6b4f04d9c475b85cce5b194650bab 100644
--- a/dumux/discretization/cellcentered/mpfa/properties.hh
+++ b/dumux/discretization/cellcentered/mpfa/properties.hh
@@ -81,10 +81,7 @@ public:
 SET_PROP(CCMpfaModel, DualGridNodalIndexSet)
 {
 private:
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
-
-    // Use the grid view's index type for grid indices
-    using GI = typename GridView::IndexSet::IndexType;
+    using GV = typename GET_PROP_TYPE(TypeTag, GridView);
 
     // per default, use uint8_t as iv-local index type
     using LI = std::uint8_t;
@@ -95,32 +92,48 @@ private:
     // maximum admissible number of elements around a node
     // if for a given grid this number is still not high enough,
     // overwrite this property in your problem with a higher number
-    static constexpr int dim = GridView::dimension;
+    static constexpr int dim = GV::dimension;
     static constexpr int maxE = dim == 3 ? 45 : 15;
 
 public:
-    using type = CCMpfaDualGridNodalIndexSet<GI, LI, dim, maxE, maxB>;
+    using type = CCMpfaDualGridNodalIndexSet<GV, LI, dim, maxE, maxB>;
 };
 
 //! The mpfa helper class
-SET_TYPE_PROP(CCMpfaModel, MpfaHelper, CCMpfaHelper<TypeTag>);
+SET_PROP(CCMpfaModel, MpfaHelper)
+{
+private:
+    using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
+public:
+    using type = CCMpfaHelper< FVGridGeometry >;
+};
 
 //! Per default, we use the dynamic mpfa-o interaction volume
 SET_PROP(CCMpfaModel, PrimaryInteractionVolume)
 {
-private:
-    //! use the default traits
-    using Traits = CCMpfaODefaultInteractionVolumeTraits< TypeTag >;
 public:
-    using type = CCMpfaOInteractionVolume< Traits >;
+    using type = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume);
 };
 
-//! Per default, we use the dynamic mpfa-o interaction volume as secondary type
+//! Per default, we use the mpfa-o interaction volume as secondary type
 SET_PROP(CCMpfaModel, SecondaryInteractionVolume)
 {
 private:
-    //! use the default traits
-    using Traits = CCMpfaODefaultInteractionVolumeTraits< TypeTag >;
+    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    using NodalIndexSet = typename GET_PROP_TYPE(TypeTag, DualGridNodalIndexSet);
+
+    // set up the physics Traits
+    struct PhysicsTraits
+    {
+        static constexpr bool enableAdvection = GET_PROP_VALUE(TypeTag, EnableAdvection);
+        static constexpr bool enableMolecularDiffusion = GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion);
+        static constexpr bool enableHeatConduction = GET_PROP_VALUE(TypeTag, EnableEnergyBalance);
+
+        static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases);
+        static constexpr int numComponents = GET_PROP_VALUE(TypeTag, NumComponents);
+    };
+    // use the default traits
+    using Traits = CCMpfaODefaultInteractionVolumeTraits< NodalIndexSet, Scalar, PhysicsTraits >;
 public:
     using type = CCMpfaOInteractionVolume< Traits >;
 };
@@ -148,10 +161,10 @@ private:
                                                                       PrimaryIV,
                                                                       SecondaryIV >;
 
-        template< class FVGridGeometry, bool enableCache >
-        using LocalView = CCMpfaFVElementGeometry<FVGridGeometry, enableCache>;
+        template< class FVGridGeometry, bool enableGeomCache >
+        using LocalView = CCMpfaFVElementGeometry<FVGridGeometry, enableGeomCache>;
 
-        //! Per default, we use the o-method and thus the simple assembly map
+        //! Use the correct connectivity map depending on mpfa scheme (obtain from primary iv)
         template< class FVGridGeometry >
         using ConnectivityMap = CCMpfaConnectivityMap<FVGridGeometry, FVGridGeometry::GridIVIndexSets::PrimaryInteractionVolume::MpfaMethod>;
     };