diff --git a/dumux/discretization/cellcentered/mpfa/fickslaw.hh b/dumux/discretization/cellcentered/mpfa/fickslaw.hh
index 7d13e5c514271edd32753af26be2437caaf6e5cc..3d5e759d4d95babc40e4bd7a5de687110319cde0 100644
--- a/dumux/discretization/cellcentered/mpfa/fickslaw.hh
+++ b/dumux/discretization/cellcentered/mpfa/fickslaw.hh
@@ -46,6 +46,9 @@ class FicksLawImplementation<TypeTag, DiscretizationMethod::ccmpfa>
     using GridView = GetPropType<TypeTag, Properties::GridView>;
     using Element = typename GridView::template Codim<0>::Entity;
 
+    static constexpr int dim = GridView::dimension;
+    static constexpr int dimWorld = GridView::dimensionworld;
+
     using FVGridGeometry = GetPropType<TypeTag, Properties::FVGridGeometry>;
     using FVElementGeometry = typename FVGridGeometry::LocalView;
     using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
@@ -79,12 +82,12 @@ class FicksLawImplementation<TypeTag, DiscretizationMethod::ccmpfa>
                 scvfFluxVarsCache.updateDiffusion(fluxVarsCacheFiller.secondaryInteractionVolume(),
                                                   fluxVarsCacheFiller.secondaryIvLocalFaceData(),
                                                   fluxVarsCacheFiller.secondaryIvDataHandle(),
-                                                  scvf, phaseIdx, compIdx);
+                                                  phaseIdx, compIdx);
             else
                 scvfFluxVarsCache.updateDiffusion(fluxVarsCacheFiller.primaryInteractionVolume(),
                                                   fluxVarsCacheFiller.primaryIvLocalFaceData(),
                                                   fluxVarsCacheFiller.primaryIvDataHandle(),
-                                                  scvf, phaseIdx, compIdx);
+                                                  phaseIdx, compIdx);
         }
     };
 
@@ -94,24 +97,19 @@ class FicksLawImplementation<TypeTag, DiscretizationMethod::ccmpfa>
         using DualGridNodalIndexSet = GetPropType<TypeTag, Properties::DualGridNodalIndexSet>;
         using Stencil = typename DualGridNodalIndexSet::NodalGridStencilType;
 
-        using MpfaHelper = typename FVGridGeometry::MpfaHelper;
-        static constexpr bool considerSecondaryIVs = MpfaHelper::considerSecondaryIVs();
-
-        using PrimaryInteractionVolume = GetPropType<TypeTag, Properties::PrimaryInteractionVolume>;
-        using PrimaryIvLocalFaceData = typename PrimaryInteractionVolume::Traits::LocalFaceData;
-        using PrimaryIvDataHandle = typename ElementFluxVariablesCache::PrimaryIvDataHandle;
-        using PrimaryIvCellVector = typename PrimaryInteractionVolume::Traits::MatVecTraits::CellVector;
-        using PrimaryIvTij = typename PrimaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type;
+        static constexpr int numPhases = GetPropType<TypeTag, Properties::ModelTraits>::numPhases();
+        static constexpr bool considerSecondaryIVs = FVGridGeometry::MpfaHelper::considerSecondaryIVs();
+        using PrimaryDataHandle = typename ElementFluxVariablesCache::PrimaryIvDataHandle::DiffusionHandle;
+        using SecondaryDataHandle = typename ElementFluxVariablesCache::SecondaryIvDataHandle::DiffusionHandle;
 
-        using SecondaryInteractionVolume = GetPropType<TypeTag, Properties::SecondaryInteractionVolume>;
-        using SecondaryIvLocalFaceData = typename SecondaryInteractionVolume::Traits::LocalFaceData;
-        using SecondaryIvDataHandle = typename ElementFluxVariablesCache::SecondaryIvDataHandle;
-        using SecondaryIvCellVector = typename SecondaryInteractionVolume::Traits::MatVecTraits::CellVector;
-        using SecondaryIvTij = typename SecondaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type;
+        //! sets the pointer to the data handle (overload for secondary data handles)
+        template< bool doSecondary = considerSecondaryIVs, std::enable_if_t<doSecondary, int> = 0 >
+        void setHandlePointer_(const SecondaryDataHandle& dataHandle)
+        { secondaryHandlePtr_ = &dataHandle; }
 
-        static constexpr int dim = GridView::dimension;
-        static constexpr int dimWorld = GridView::dimensionworld;
-        static constexpr int numPhases = GetPropType<TypeTag, Properties::ModelTraits>::numPhases();
+        //! sets the pointer to the data handle (overload for primary data handles)
+        void setHandlePointer_(const PrimaryDataHandle& dataHandle)
+        { primaryHandlePtr_ = &dataHandle; }
 
     public:
         // export filler type
@@ -124,104 +122,39 @@ class FicksLawImplementation<TypeTag, DiscretizationMethod::ccmpfa>
          * \param iv The interaction volume this scvf is embedded in
          * \param localFaceData iv-local info on this scvf
          * \param dataHandle Transmissibility matrix & gravity data of this iv
-         * \param scvf The sub-control volume face
          */
-        void updateDiffusion(const PrimaryInteractionVolume& iv,
-                             const PrimaryIvLocalFaceData& localFaceData,
-                             const PrimaryIvDataHandle& dataHandle,
-                             const SubControlVolumeFace &scvf,
+        template<class IV, class LocalFaceData, class DataHandle>
+        void updateDiffusion(const IV& iv,
+                             const LocalFaceData& localFaceData,
+                             const DataHandle& dataHandle,
                              unsigned int phaseIdx, unsigned int compIdx)
         {
-            const auto& handle = dataHandle.diffusionHandle();
-
             stencil_[phaseIdx][compIdx] = &iv.stencil();
             switchFluxSign_[phaseIdx][compIdx] = localFaceData.isOutsideFace();
-
-            // store pointer to the mole fraction vector of this iv
-            primaryXj_[phaseIdx][compIdx] = &handle.uj();
-
-            const auto ivLocalIdx = localFaceData.ivLocalScvfIndex();
-            if (dim == dimWorld)
-                primaryTij_[phaseIdx][compIdx] = &handle.T()[ivLocalIdx];
-            else
-                primaryTij_[phaseIdx][compIdx] = localFaceData.isOutsideFace()
-                                                 ? &handle.tijOutside()[ivLocalIdx][localFaceData.scvfLocalOutsideScvfIndex()]
-                                                 : &handle.T()[ivLocalIdx];
+            setHandlePointer_(dataHandle.diffusionHandle());
         }
 
-        /*!
-         * \brief Update cached objects (transmissibilities).
-         *        This is used for updates with secondary interaction volumes.
-         *
-         * \param iv The interaction volume this scvf is embedded in
-         * \param localFaceData iv-local info on this scvf
-         * \param dataHandle Transmissibility matrix & gravity data of this iv
-         * \param scvf The sub-control volume face
-         */
-        template< bool doSecondary = considerSecondaryIVs, std::enable_if_t<doSecondary, int > = 0 >
-        void updateDiffusion(const SecondaryInteractionVolume& iv,
-                             const SecondaryIvLocalFaceData& localFaceData,
-                             const SecondaryIvDataHandle& dataHandle,
-                             const SubControlVolumeFace &scvf,
-                             unsigned int phaseIdx, unsigned int compIdx)
-        {
-            const auto& handle = dataHandle.diffusionHandle();
-
-            stencil_[phaseIdx][compIdx] = &iv.stencil();
-            switchFluxSign_[phaseIdx][compIdx] = localFaceData.isOutsideFace();
-
-            // store pointer to the mole fraction vector of this iv
-            secondaryXj_[phaseIdx][compIdx] = &handle.uj();
+        //! The stencils corresponding to the transmissibilities
+        const Stencil& diffusionStencil(unsigned int phaseIdx, unsigned int compIdx) const
+        { return *stencil_[phaseIdx][compIdx]; }
 
-            const auto ivLocalIdx = localFaceData.ivLocalScvfIndex();
-            if (dim == dimWorld)
-                secondaryTij_[phaseIdx][compIdx] = &handle.T()[ivLocalIdx];
-            else
-                secondaryTij_[phaseIdx][compIdx] = localFaceData.isOutsideFace()
-                                                   ? &handle.tijOutside()[ivLocalIdx][localFaceData.scvfLocalOutsideScvfIndex()]
-                                                   : &handle.T()[ivLocalIdx];
-        }
+        //! The corresponding data handles
+        const PrimaryDataHandle& diffusionPrimaryDataHandle() const { return *primaryHandlePtr_; }
+        const SecondaryDataHandle& diffusionSecondaryDataHandle() const { return *secondaryHandlePtr_; }
 
-        //! 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
-        //! to take the negative value of the fluxes due to the flipped normal vector.
-        //! This function returns whether or not this scvf is an "outside" face in the iv.
+        //! Returns whether or not this scvf is an "outside" face in the scope of the iv.
         bool diffusionSwitchFluxSign(unsigned int phaseIdx, unsigned int compIdx) const
         { return switchFluxSign_[phaseIdx][compIdx]; }
 
-        //! Coefficients for the cell (& Dirichlet) unknowns in flux expressions (primary type)
-        const PrimaryIvTij& diffusionTijPrimaryIv(unsigned int phaseIdx, unsigned int compIdx) const
-        { return *primaryTij_[phaseIdx][compIdx]; }
-
-        //! Coefficients for the cell (& Dirichlet) unknowns in flux expressions (secondary type)
-        const SecondaryIvTij& diffusionTijSecondaryIv(unsigned int phaseIdx, unsigned int compIdx) const
-        { return *secondaryTij_[phaseIdx][compIdx]; }
-
-        //! 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 (& 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
-        const Stencil& diffusionStencil(unsigned int phaseIdx, unsigned int compIdx) const
-        { return *stencil_[phaseIdx][compIdx]; }
 
     private:
+        //! phase-/component- specific data
         std::array< std::array<bool, numComponents>, numPhases > switchFluxSign_;
-
-        //! The stencils, i.e. the grid indices j
         std::array< std::array<const Stencil*, numComponents>, numPhases > stencil_;
 
-        //! The transmissibilities such that f = Tij*xj
-        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 PrimaryIvCellVector*, numComponents>, numPhases > primaryXj_;
-        std::array< std::array<const SecondaryIvCellVector*, numComponents>, numPhases > secondaryXj_;
+        //! pointers to the corresponding iv-data handles
+        const PrimaryDataHandle* primaryHandlePtr_;
+        const SecondaryDataHandle* secondaryHandlePtr_;
     };
 
 public:
@@ -259,25 +192,17 @@ public:
             // calculate the density at the interface
             const auto rho = interpolateDensity(elemVolVars, scvf, phaseIdx);
 
-            // calculate Tij*xj
-            Scalar flux;
+            // compute the flux
             if (fluxVarsCache.usesSecondaryIv())
-            {
-                const auto& tij = fluxVarsCache.diffusionTijSecondaryIv(phaseIdx, compIdx);
-                const auto& xj = fluxVarsCache.moleFractionsSecondaryIv(phaseIdx, compIdx);
-                flux = tij*xj;
-            }
+                componentFlux[compIdx] = rho*effFactor*computeVolumeFlux(problem,
+                                                                         fluxVarsCache,
+                                                                         fluxVarsCache.diffusionSecondaryDataHandle(),
+                                                                         phaseIdx, compIdx);
             else
-            {
-                const auto& tij = fluxVarsCache.diffusionTijPrimaryIv(phaseIdx, compIdx);
-                const auto& xj = fluxVarsCache.moleFractionsPrimaryIv(phaseIdx, compIdx);
-                flux = tij*xj;
-            }
-
-            if (fluxVarsCache.diffusionSwitchFluxSign(phaseIdx, compIdx))
-                flux *= -1.0;
-
-            componentFlux[compIdx] = flux*rho*effFactor;
+                componentFlux[compIdx] = rho*effFactor*computeVolumeFlux(problem,
+                                                                         fluxVarsCache,
+                                                                         fluxVarsCache.diffusionPrimaryDataHandle(),
+                                                                         phaseIdx, compIdx);
         }
 
         // accumulate the phase component flux
@@ -289,6 +214,32 @@ public:
     }
 
 private:
+    template< class Problem, class FluxVarsCache, class DataHandle >
+    static Scalar computeVolumeFlux(const Problem& problem,
+                                    const FluxVarsCache& cache,
+                                    const DataHandle& dataHandle,
+                                    int phaseIdx, int compIdx)
+    {
+        dataHandle.setPhaseIndex(phaseIdx);
+        dataHandle.setComponentIndex(compIdx);
+
+        const bool switchSign = cache.diffusionSwitchFluxSign(phaseIdx, compIdx);
+
+        const auto localFaceIdx = cache.ivLocalFaceIndex();
+        const auto idxInOutside = cache.indexInOutsideFaces();
+        const auto& xj = dataHandle.uj();
+        const auto& tij = dim == dimWorld ? dataHandle.T()[localFaceIdx]
+                                          : (!switchSign ? dataHandle.T()[localFaceIdx]
+                                                         : dataHandle.tijOutside()[localFaceIdx][idxInOutside]);
+        Scalar scvfFlux = tij*xj;
+
+        // switch the sign if necessary
+        if (cache.advectionSwitchFluxSign())
+            scvfFlux *= -1.0;
+
+        return scvfFlux;
+    }
+
     //! compute the density at branching facets for network grids as arithmetic mean
     static Scalar interpolateDensity(const ElementVolumeVariables& elemVolVars,
                                      const SubControlVolumeFace& scvf,