diff --git a/ProcessLib/ComponentTransport/ComponentTransportFEM.h b/ProcessLib/ComponentTransport/ComponentTransportFEM.h
index 6922dc8a13437d0dab6dea30f1632eb567d1e8da..3a3196da2f9050e7ebfdd657f46b5f7577a63ded 100644
--- a/ProcessLib/ComponentTransport/ComponentTransportFEM.h
+++ b/ProcessLib/ComponentTransport/ComponentTransportFEM.h
@@ -23,6 +23,7 @@
 #include "NumLib/Fem/FiniteElement/TemplateIsoparametric.h"
 #include "NumLib/Fem/ShapeMatrixPolicy.h"
 #include "NumLib/Function/Interpolation.h"
+#include "ProcessLib/CoupledSolutionsForStaggeredScheme.h"
 #include "ProcessLib/LocalAssemblerInterface.h"
 #include "ProcessLib/Parameter/Parameter.h"
 #include "ProcessLib/ProcessVariable.h"
@@ -53,22 +54,42 @@ class ComponentTransportLocalAssemblerInterface
       public NumLib::ExtrapolatableElement
 {
 public:
+    ComponentTransportLocalAssemblerInterface() : _coupled_solutions(nullptr) {}
+
+    void setStaggeredCoupledSolutions(
+        std::size_t const /*mesh_item_id*/,
+        CoupledSolutionsForStaggeredScheme* const coupling_term)
+    {
+        _coupled_solutions = coupling_term;
+    }
+
     virtual std::vector<double> const& getIntPtDarcyVelocity(
         const double t,
         GlobalVector const& current_solution,
         NumLib::LocalToGlobalIndexMap const& dof_table,
         std::vector<double>& cache) const = 0;
+
+protected:
+    CoupledSolutionsForStaggeredScheme* _coupled_solutions;
 };
 
 template <typename ShapeFunction, typename IntegrationMethod,
           unsigned GlobalDim>
 class LocalAssemblerData : public ComponentTransportLocalAssemblerInterface
 {
-    // Pressure always first
+    // When staggered scheme is adopted, nodal pressure and nodal concentration
+    // are accessed by process id.
+    static const int hydraulic_process_id = 0;
+    static const int transport_process_id = 1;
+
+    // When monolithic scheme is adopted, nodal pressure and nodal concentration
+    // are accessed by vector index.
     static const int pressure_index = 0;
+    static const int first_concentration_index = ShapeFunction::NPOINTS;
+
     static const int pressure_size = ShapeFunction::NPOINTS;
-    // Size of concentration to each component
-    static const int concentration_size = ShapeFunction::NPOINTS;
+    static const int concentration_size =
+        ShapeFunction::NPOINTS;  // per component
 
     using ShapeMatricesType = ShapeMatrixPolicyType<ShapeFunction, GlobalDim>;
     using ShapeMatrices = typename ShapeMatricesType::ShapeMatrices;
@@ -98,19 +119,13 @@ public:
         bool is_axially_symmetric,
         unsigned const integration_order,
         ComponentTransportProcessData const& process_data,
-        std::vector<std::reference_wrapper<ProcessVariable>> const&
-            per_process_variables)
+        std::vector<std::reference_wrapper<ProcessVariable>>
+            transport_process_variables)
         : _element(element),
           _process_data(process_data),
           _integration_method(integration_order),
-          _per_process_variables(per_process_variables)
+          _transport_process_variables(transport_process_variables)
     {
-        // This assertion is valid only if all nodal d.o.f. use the same shape
-        // matrices.
-        // _per_process_variables.size() can represent number of nodal DOFs
-        // regardless of what scheme is adopted.
-        assert(local_matrix_size ==
-               ShapeFunction::NPOINTS * _per_process_variables.size());
         (void)local_matrix_size;
 
         unsigned const n_integration_points =
@@ -138,9 +153,8 @@ public:
                   std::vector<double>& local_b_data) override
     {
         auto const local_matrix_size = local_x.size();
-
-        int const num_nodal_dof = _per_process_variables.size();
-
+        // Nodal DOFs include pressure
+        int const num_nodal_dof = 1 + _transport_process_variables.size();
         // This assertion is valid only if all nodal d.o.f. use the same shape
         // matrices.
         assert(local_matrix_size == ShapeFunction::NPOINTS * num_nodal_dof);
@@ -162,7 +176,6 @@ public:
         auto local_p = Eigen::Map<const NodalVectorType>(
             &local_x[pressure_index], pressure_size);
 
-        // Nodal DOFs include pressure
         auto const number_of_components = num_nodal_dof - 1;
         for (int component_id = 0; component_id < number_of_components;
              ++component_id)
@@ -212,9 +225,6 @@ public:
         Eigen::Ref<LocalBlockMatrixType> Mpp,
         Eigen::Ref<LocalSegmentVectorType> Bp)
     {
-        assert(component_id <=
-               static_cast<int>(_per_process_variables.size() - 1));
-
         unsigned const n_integration_points =
             _integration_method.getNumberOfPoints();
 
@@ -238,9 +248,9 @@ public:
         // name. Components are shifted by one because the first one is always
         // pressure.
         auto const& component = phase.component(
-            _per_process_variables[component_id + 1].get().getName());
+            _transport_process_variables[component_id].get().getName());
 
-        for (std::size_t ip(0); ip < n_integration_points; ++ip)
+        for (unsigned ip(0); ip < n_integration_points; ++ip)
         {
             pos.setIntegrationPoint(ip);
 
@@ -358,27 +368,330 @@ public:
         }
     }
 
+    void assembleForStaggeredScheme(
+        double const t,
+        std::vector<double>& local_M_data,
+        std::vector<double>& local_K_data,
+        std::vector<double>& local_b_data,
+        LocalCoupledSolutions const& coupled_xs) override
+    {
+        if (coupled_xs.process_id == hydraulic_process_id)
+        {
+            assembleHydraulicEquation(t, local_M_data, local_K_data,
+                                      local_b_data, coupled_xs);
+        }
+        else
+        {
+            // Go for assembling in an order of transport process id.
+            assembleComponentTransportEquation(t, local_M_data, local_K_data,
+                                               local_b_data, coupled_xs);
+        }
+    }
+
+    void assembleHydraulicEquation(double const t,
+                                   std::vector<double>& local_M_data,
+                                   std::vector<double>& local_K_data,
+                                   std::vector<double>& local_b_data,
+                                   LocalCoupledSolutions const& coupled_xs)
+    {
+        auto local_p = Eigen::Map<const NodalVectorType>(
+            coupled_xs.local_coupled_xs[hydraulic_process_id].data(),
+            pressure_size);
+        auto local_C = Eigen::Map<const NodalVectorType>(
+            coupled_xs.local_coupled_xs[transport_process_id].data(),
+            concentration_size);
+        auto local_C0 = Eigen::Map<const NodalVectorType>(
+            coupled_xs.local_coupled_xs0[transport_process_id].data(),
+            concentration_size);
+
+        auto const dt = coupled_xs.dt;
+
+        auto local_M = MathLib::createZeroedMatrix<LocalBlockMatrixType>(
+            local_M_data, pressure_size, pressure_size);
+        auto local_K = MathLib::createZeroedMatrix<LocalBlockMatrixType>(
+            local_K_data, pressure_size, pressure_size);
+        auto local_b = MathLib::createZeroedVector<LocalSegmentVectorType>(
+            local_b_data, pressure_size);
+
+        unsigned const n_integration_points =
+            _integration_method.getNumberOfPoints();
+
+        SpatialPosition pos;
+        pos.setElementID(_element.getID());
+
+        auto const& b = _process_data.specific_body_force;
+
+        MaterialLib::Fluid::FluidProperty::ArrayType vars;
+
+        for (unsigned ip(0); ip < n_integration_points; ++ip)
+        {
+            pos.setIntegrationPoint(ip);
+
+            auto const& ip_data = _ip_data[ip];
+            auto const& N = ip_data.N;
+            auto const& dNdx = ip_data.dNdx;
+            auto const& w = ip_data.integration_weight;
+
+            double C_int_pt = 0.0;
+            double p_int_pt = 0.0;
+
+            NumLib::shapeFunctionInterpolate(local_C, N, C_int_pt);
+            NumLib::shapeFunctionInterpolate(local_p, N, p_int_pt);
+
+            // porosity model
+            auto const porosity =
+                _process_data.porous_media_properties.getPorosity(t, pos)
+                    .getValue(t, pos, 0.0, C_int_pt);
+
+            // Use the fluid density model to compute the density
+            // TODO: Concentration of which component as one of arguments for
+            // calculation of fluid density
+            vars[static_cast<int>(
+                MaterialLib::Fluid::PropertyVariableType::C)] = C_int_pt;
+            vars[static_cast<int>(
+                MaterialLib::Fluid::PropertyVariableType::p)] = p_int_pt;
+            auto const density = _process_data.fluid_properties->getValue(
+                MaterialLib::Fluid::FluidPropertyType::Density, vars);
+
+            auto const& K =
+                _process_data.porous_media_properties.getIntrinsicPermeability(
+                    t, pos).getValue(t, pos, 0.0, 0.0);
+            // Use the viscosity model to compute the viscosity
+            auto const mu = _process_data.fluid_properties->getValue(
+                MaterialLib::Fluid::FluidPropertyType::Viscosity, vars);
+
+            GlobalDimMatrixType const K_over_mu = K / mu;
+
+            const double drho_dp = _process_data.fluid_properties->getdValue(
+                MaterialLib::Fluid::FluidPropertyType::Density,
+                vars,
+                MaterialLib::Fluid::PropertyVariableType::p);
+            const double drho_dC = _process_data.fluid_properties->getdValue(
+                MaterialLib::Fluid::FluidPropertyType::Density,
+                vars,
+                MaterialLib::Fluid::PropertyVariableType::C);
+
+            // matrix assembly
+            local_M.noalias() += w * N.transpose() * porosity * drho_dp * N;
+            local_K.noalias() +=
+                w * dNdx.transpose() * density * K_over_mu * dNdx;
+
+            if (_process_data.has_gravity)
+                local_b.noalias() +=
+                    w * density * density * dNdx.transpose() * K_over_mu * b;
+
+            // coupling term
+            {
+                double C0_int_pt = 0.0;
+                NumLib::shapeFunctionInterpolate(local_C0, N, C0_int_pt);
+
+                local_b.noalias() -= w * N.transpose() * porosity * drho_dC *
+                                     (C_int_pt - C0_int_pt) / dt;
+            }
+        }
+    }
+
+    void assembleComponentTransportEquation(
+        double const t, std::vector<double>& local_M_data,
+        std::vector<double>& local_K_data,
+        std::vector<double>& /*local_b_data*/,
+        LocalCoupledSolutions const& coupled_xs)
+    {
+        auto local_C = Eigen::Map<const NodalVectorType>(
+            coupled_xs.local_coupled_xs[transport_process_id].data(),
+            concentration_size);
+        auto local_p = Eigen::Map<const NodalVectorType>(
+            coupled_xs.local_coupled_xs[hydraulic_process_id].data(),
+            pressure_size);
+        auto local_p0 = Eigen::Map<const NodalVectorType>(
+            coupled_xs.local_coupled_xs0[hydraulic_process_id].data(),
+            pressure_size);
+
+        auto const dt = coupled_xs.dt;
+
+        auto local_M = MathLib::createZeroedMatrix<LocalBlockMatrixType>(
+            local_M_data, concentration_size, concentration_size);
+        auto local_K = MathLib::createZeroedMatrix<LocalBlockMatrixType>(
+            local_K_data, concentration_size, concentration_size);
+
+        unsigned const n_integration_points =
+            _integration_method.getNumberOfPoints();
+
+        SpatialPosition pos;
+        pos.setElementID(_element.getID());
+
+        auto const& b = _process_data.specific_body_force;
+
+        MaterialLib::Fluid::FluidProperty::ArrayType vars;
+
+        GlobalDimMatrixType const& I(
+            GlobalDimMatrixType::Identity(GlobalDim, GlobalDim));
+
+        auto const& medium =
+            *_process_data.media_map->getMedium(_element.getID());
+        auto const& phase = medium.phase("AqueousLiquid");
+        // Hydraulic process id is 0 and thus transport process id starts
+        // from 1.
+        auto const component_id = transport_process_id - 1;
+        auto const& component = phase.component(
+            _transport_process_variables[component_id].get().getName());
+
+        for (unsigned ip(0); ip < n_integration_points; ++ip)
+        {
+            pos.setIntegrationPoint(ip);
+
+            auto const& ip_data = _ip_data[ip];
+            auto const& N = ip_data.N;
+            auto const& dNdx = ip_data.dNdx;
+            auto const& w = ip_data.integration_weight;
+
+            double C_int_pt = 0.0;
+            double p_int_pt = 0.0;
+
+            NumLib::shapeFunctionInterpolate(local_C, N, C_int_pt);
+            NumLib::shapeFunctionInterpolate(local_p, N, p_int_pt);
+
+            // porosity model
+            auto const porosity =
+                _process_data.porous_media_properties.getPorosity(t, pos)
+                    .getValue(t, pos, 0.0, C_int_pt);
+
+            auto const retardation_factor =
+                _process_data.retardation_factor(t, pos)[0];
+
+            auto const& solute_dispersivity_transverse =
+                medium.template value<double>(
+                    MaterialPropertyLib::transversal_dispersivity);
+            auto const& solute_dispersivity_longitudinal =
+                medium.template value<double>(
+                    MaterialPropertyLib::longitudinal_dispersivity);
+
+            // Use the fluid density model to compute the density
+            vars[static_cast<int>(
+                MaterialLib::Fluid::PropertyVariableType::C)] = C_int_pt;
+            vars[static_cast<int>(
+                MaterialLib::Fluid::PropertyVariableType::p)] = p_int_pt;
+            auto const density = _process_data.fluid_properties->getValue(
+                MaterialLib::Fluid::FluidPropertyType::Density, vars);
+            auto const decay_rate = _process_data.decay_rate(t, pos)[0];
+
+            auto const& molecular_diffusion_coefficient =
+                component.template value<double>(
+                    MaterialPropertyLib::molecular_diffusion);
+
+            auto const& K =
+                _process_data.porous_media_properties.getIntrinsicPermeability(
+                    t, pos).getValue(t, pos, 0.0, 0.0);
+            // Use the viscosity model to compute the viscosity
+            auto const mu = _process_data.fluid_properties->getValue(
+                MaterialLib::Fluid::FluidPropertyType::Viscosity, vars);
+
+            GlobalDimMatrixType const K_over_mu = K / mu;
+            GlobalDimVectorType const velocity =
+                _process_data.has_gravity
+                    ? GlobalDimVectorType(-K_over_mu *
+                                          (dNdx * local_p - density * b))
+                    : GlobalDimVectorType(-K_over_mu * dNdx * local_p);
+
+            const double drho_dp = _process_data.fluid_properties->getdValue(
+                MaterialLib::Fluid::FluidPropertyType::Density,
+                vars,
+                MaterialLib::Fluid::PropertyVariableType::p);
+
+            const double drho_dC = _process_data.fluid_properties->getdValue(
+                MaterialLib::Fluid::FluidPropertyType::Density,
+                vars,
+                MaterialLib::Fluid::PropertyVariableType::C);
+            double const velocity_magnitude = velocity.norm();
+            GlobalDimMatrixType const hydrodynamic_dispersion =
+                velocity_magnitude != 0.0
+                    ? GlobalDimMatrixType(
+                          (porosity * molecular_diffusion_coefficient +
+                           solute_dispersivity_transverse *
+                               velocity_magnitude) *
+                              I +
+                          (solute_dispersivity_longitudinal -
+                           solute_dispersivity_transverse) /
+                              velocity_magnitude * velocity *
+                              velocity.transpose())
+                    : GlobalDimMatrixType(
+                          (porosity * molecular_diffusion_coefficient +
+                           solute_dispersivity_transverse *
+                               velocity_magnitude) *
+                          I);
+
+            // matrix assembly
+            local_M.noalias() += w * N.transpose() * retardation_factor *
+                                     porosity * density * N +
+                                 w * N.transpose() * retardation_factor *
+                                     porosity * C_int_pt * drho_dC * N;
+
+            // coupling term
+            {
+                double p0_int_pt = 0.0;
+                NumLib::shapeFunctionInterpolate(local_p0, N, p0_int_pt);
+
+                local_K.noalias() +=
+                    (-dNdx.transpose() * velocity * density * N +
+                     dNdx.transpose() * density * hydrodynamic_dispersion *
+                         dNdx +
+                     N.transpose() *
+                         (decay_rate * porosity * retardation_factor * density +
+                          porosity * retardation_factor * drho_dp *
+                              (p_int_pt - p0_int_pt) / dt) *
+                         N) *
+                    w;
+            }
+        }
+    }
+
     std::vector<double> const& getIntPtDarcyVelocity(
         const double t,
         GlobalVector const& current_solution,
         NumLib::LocalToGlobalIndexMap const& dof_table,
         std::vector<double>& cache) const override
     {
-        auto const n_integration_points =
-            _integration_method.getNumberOfPoints();
-
         auto const indices = NumLib::getIndices(_element.getID(), dof_table);
         assert(!indices.empty());
-        auto const local_x = current_solution.get(indices);
-
-        // Assuming that fluid density always depends on the concentration of
-        // the component placed at the first.
-        auto const concentration_index = 1 * ShapeFunction::NPOINTS;
-        // get local_C and local_p
-        auto const C_nodal_values = Eigen::Map<const NodalVectorType>(
-            &local_x[concentration_index], concentration_size);
-        auto const p_nodal_values = Eigen::Map<const NodalVectorType>(
-            &local_x[pressure_index], pressure_size);
+
+        if (_coupled_solutions == nullptr)  // monolithic scheme
+        {
+            auto const local_x = current_solution.get(indices);
+
+            // Assuming that fluid density always depends on the concentration
+            // of the component which is placed at the uppermost.
+            auto const local_p = Eigen::Map<const NodalVectorType>(
+                &local_x[pressure_index], pressure_size);
+            auto const local_C = Eigen::Map<const NodalVectorType>(
+                &local_x[first_concentration_index], concentration_size);
+
+            return calculateIntPtDarcyVelocity(t, local_p, local_C, cache);
+        }
+        else  // staggered scheme
+        {
+            std::vector<std::vector<GlobalIndexType>>
+                indices_of_all_coupled_processes(
+                    _coupled_solutions->coupled_xs.size(), indices);
+
+            auto const local_xs = getCurrentLocalSolutions(
+                *(this->_coupled_solutions), indices_of_all_coupled_processes);
+
+            auto const local_p = MathLib::toVector(local_xs[hydraulic_process_id]);
+            auto const local_C =
+                MathLib::toVector(local_xs[transport_process_id]);
+
+            return calculateIntPtDarcyVelocity(t, local_p, local_C, cache);
+        }
+    }
+
+    std::vector<double> const& calculateIntPtDarcyVelocity(
+        const double t,
+        Eigen::Ref<const NodalVectorType> const& p_nodal_values,
+        Eigen::Ref<const NodalVectorType> const& C_nodal_values,
+        std::vector<double>& cache) const
+    {
+        auto const n_integration_points =
+            _integration_method.getNumberOfPoints();
 
         cache.clear();
         auto cache_mat = MathLib::createZeroedMatrix<
@@ -430,7 +743,6 @@ public:
         return cache;
     }
 
-
     Eigen::Map<const Eigen::RowVectorXd> getShapeMatrix(
         const unsigned integration_point) const override
     {
@@ -443,6 +755,31 @@ public:
     Eigen::Vector3d getFlux(MathLib::Point3d const& pnt_local_coords,
                             double const t,
                             std::vector<double> const& local_x) const override
+    {
+        auto const local_p = Eigen::Map<const NodalVectorType>(
+            &local_x[pressure_index], pressure_size);
+        auto const local_C = Eigen::Map<const NodalVectorType>(
+            &local_x[first_concentration_index], concentration_size);
+
+        return calculateFlux(pnt_local_coords, t, local_p, local_C);
+    }
+
+    Eigen::Vector3d getFlux(
+        MathLib::Point3d const& pnt_local_coords,
+        double const t,
+        std::vector<std::vector<double>> const& local_xs) const override
+    {
+        auto const local_p = MathLib::toVector(local_xs[hydraulic_process_id]);
+        auto const local_C = MathLib::toVector(local_xs[transport_process_id]);
+
+        return calculateFlux(pnt_local_coords, t, local_p, local_C);
+    }
+
+    Eigen::Vector3d calculateFlux(
+        MathLib::Point3d const& pnt_local_coords,
+        double const t,
+        Eigen::Ref<const NodalVectorType> const& p_nodal_values,
+        Eigen::Ref<const NodalVectorType> const& C_nodal_values) const
     {
         // eval shape matrices at given point
         auto const shape_matrices = [&]() {
@@ -463,12 +800,6 @@ public:
             return shape_matrices;
         }();
 
-        auto const concentration_index = 1 * ShapeFunction::NPOINTS;
-        auto const C_nodal_values = Eigen::Map<const NodalVectorType>(
-            &local_x[concentration_index], concentration_size);
-        auto const p_nodal_values = Eigen::Map<const NodalVectorType>(
-            &local_x[pressure_index], pressure_size);
-
         SpatialPosition pos;
         pos.setElementID(_element.getID());
 
@@ -516,8 +847,8 @@ private:
     ComponentTransportProcessData const& _process_data;
 
     IntegrationMethod const _integration_method;
-    std::vector<std::reference_wrapper<ProcessVariable>> const&
-        _per_process_variables;
+    std::vector<std::reference_wrapper<ProcessVariable>> const
+        _transport_process_variables;
 
     std::vector<
         IntegrationPointData<NodalRowVectorType, GlobalDimNodalMatrixType>,
diff --git a/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp b/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp
index b4a7f72badb08fc3c7505413a0c30861557edcf2..40aa75f8e6dd3d693f9cfdaeb6d4f743abb0659f 100644
--- a/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp
+++ b/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp
@@ -47,11 +47,29 @@ void ComponentTransportProcess::initializeConcreteProcess(
 {
     const int process_id = 0;
     ProcessLib::ProcessVariable const& pv = getProcessVariables(process_id)[0];
+
+    std::vector<std::reference_wrapper<ProcessLib::ProcessVariable>>
+        transport_process_variables;
+    if (_use_monolithic_scheme)
+    {
+        for (auto pv_iter = std::next(_process_variables[process_id].begin());
+             pv_iter != _process_variables[process_id].end();
+             ++pv_iter)
+            transport_process_variables.push_back(*pv_iter);
+    }
+    else
+    {
+        for (auto pv_iter = std::next(_process_variables.begin());
+             pv_iter != _process_variables.end();
+             ++pv_iter)
+            transport_process_variables.push_back((*pv_iter)[0]);
+    }
+
     ProcessLib::createLocalAssemblers<LocalAssemblerData>(
         mesh.getDimension(), mesh.getElements(), dof_table,
         pv.getShapeFunctionOrder(), _local_assemblers,
         mesh.isAxiallySymmetric(), integration_order, _process_data,
-        _process_variables[process_id]);
+        transport_process_variables);
 
     _secondary_variables.addSecondaryVariable(
         "darcy_velocity",
@@ -73,14 +91,38 @@ void ComponentTransportProcess::assembleConcreteProcess(
     ProcessLib::ProcessVariable const& pv = getProcessVariables(process_id)[0];
 
     std::vector<std::reference_wrapper<NumLib::LocalToGlobalIndexMap>>
-        dof_table = {std::ref(*_local_to_global_index_map)};
+        dof_tables;
+    if (_use_monolithic_scheme)
+    {
+        dof_tables.push_back(std::ref(*_local_to_global_index_map));
+    }
+    else
+    {
+        setCoupledSolutionsOfPreviousTimeStep();
+        std::generate_n(
+            std::back_inserter(dof_tables), _process_variables.size(),
+            [&]() { return std::ref(*_local_to_global_index_map); });
+    }
     // Call global assembler for each local assembly item.
     GlobalExecutor::executeSelectedMemberDereferenced(
         _global_assembler, &VectorMatrixAssembler::assemble, _local_assemblers,
-        pv.getActiveElementIDs(), dof_table, t, x, M, K, b,
+        pv.getActiveElementIDs(), dof_tables, t, x, M, K, b,
         _coupled_solutions);
 }
 
+void ComponentTransportProcess::setCoupledSolutionsOfPreviousTimeStep()
+{
+    unsigned const number_of_coupled_solutions =
+        _coupled_solutions->coupled_xs.size();
+    _coupled_solutions->coupled_xs_t0.clear();
+    _coupled_solutions->coupled_xs_t0.reserve(number_of_coupled_solutions);
+    for (unsigned i = 0; i < number_of_coupled_solutions; ++i)
+    {
+        auto const& x_t0 = _xs_previous_timestep[i];
+        _coupled_solutions->coupled_xs_t0.emplace_back(x_t0.get());
+    }
+}
+
 void ComponentTransportProcess::assembleWithJacobianConcreteProcess(
     const double t, GlobalVector const& x, GlobalVector const& xdot,
     const double dxdot_dx, const double dx_dx, GlobalMatrix& M, GlobalMatrix& K,
@@ -107,8 +149,58 @@ Eigen::Vector3d ComponentTransportProcess::getFlux(std::size_t const element_id,
     std::vector<GlobalIndexType> indices_cache;
     auto const r_c_indices = NumLib::getRowColumnIndices(
         element_id, *_local_to_global_index_map, indices_cache);
-    std::vector<double> local_x(x.get(r_c_indices.rows));
-    return _local_assemblers[element_id]->getFlux(p, t, local_x);
+
+    if (_use_monolithic_scheme)
+    {
+        std::vector<double> local_x(x.get(r_c_indices.rows));
+
+        return _local_assemblers[element_id]->getFlux(p, t, local_x);
+    }
+    else
+    {
+        std::vector<std::vector<GlobalIndexType>>
+            indices_of_all_coupled_processes{
+                _coupled_solutions->coupled_xs.size(), r_c_indices.rows};
+        auto const local_xs = getCurrentLocalSolutions(
+            *(this->_coupled_solutions), indices_of_all_coupled_processes);
+
+        return _local_assemblers[element_id]->getFlux(p, t, local_xs);
+    }
+}
+
+void ComponentTransportProcess::
+    setCoupledTermForTheStaggeredSchemeToLocalAssemblers()
+{
+    DBUG("Set the coupled term for the staggered scheme to local assembers.");
+
+    const int process_id =
+        _use_monolithic_scheme ? 0 : _coupled_solutions->process_id;
+    ProcessLib::ProcessVariable const& pv = getProcessVariables(process_id)[0];
+    GlobalExecutor::executeSelectedMemberOnDereferenced(
+        &ComponentTransportLocalAssemblerInterface::
+            setStaggeredCoupledSolutions,
+        _local_assemblers, pv.getActiveElementIDs(), _coupled_solutions);
+}
+
+void ComponentTransportProcess::preTimestepConcreteProcess(
+    GlobalVector const& x, const double /*t*/, const double /*delta_t*/,
+    int const process_id)
+{
+    if (_use_monolithic_scheme)
+    {
+        return;
+    }
+
+    if (!_xs_previous_timestep[process_id])
+    {
+        _xs_previous_timestep[process_id] =
+            MathLib::MatrixVectorTraits<GlobalVector>::newInstance(x);
+    }
+    else
+    {
+        auto& x0 = *_xs_previous_timestep[process_id];
+        MathLib::LinAlg::copy(x, x0);
+    }
 }
 
 void ComponentTransportProcess::postTimestepConcreteProcess(
@@ -124,7 +216,7 @@ void ComponentTransportProcess::postTimestepConcreteProcess(
             "The condition of process_id = 0 must be satisfied for "
             "monolithic ComponentTransportProcess, which is a single process.");
     }
-    if (!_use_monolithic_scheme && process_id != 1)
+    if (!_use_monolithic_scheme && process_id != 0)
     {
         DBUG(
             "This is the transport part of the staggered "
diff --git a/ProcessLib/ComponentTransport/ComponentTransportProcess.h b/ProcessLib/ComponentTransport/ComponentTransportProcess.h
index 341fb256b50c17bdb713bf48c0bbfb9196d0dca6..04b1a141a403692ac775813935f48ac0cd44c090 100644
--- a/ProcessLib/ComponentTransport/ComponentTransportProcess.h
+++ b/ProcessLib/ComponentTransport/ComponentTransportProcess.h
@@ -112,6 +112,12 @@ public:
                             MathLib::Point3d const& p, double const t,
                             GlobalVector const& x) const override;
 
+    void setCoupledTermForTheStaggeredSchemeToLocalAssemblers() override;
+
+    void preTimestepConcreteProcess(GlobalVector const& x, const double /*t*/,
+                                    const double /*delta_t*/,
+                                    int const process_id) override;
+
     void postTimestepConcreteProcess(GlobalVector const& x,
                                      const double t,
                                      const double delta_t,
@@ -132,11 +138,16 @@ private:
         const double dxdot_dx, const double dx_dx, GlobalMatrix& M,
         GlobalMatrix& K, GlobalVector& b, GlobalMatrix& Jac) override;
 
+    void setCoupledSolutionsOfPreviousTimeStep();
+
     ComponentTransportProcessData _process_data;
 
     std::vector<std::unique_ptr<ComponentTransportLocalAssemblerInterface>>
         _local_assemblers;
 
+    /// Solutions of the previous time step
+    std::array<std::unique_ptr<GlobalVector>, 2> _xs_previous_timestep;
+
     std::unique_ptr<ProcessLib::SurfaceFluxData> _surfaceflux;
 };
 
diff --git a/ProcessLib/LocalAssemblerInterface.h b/ProcessLib/LocalAssemblerInterface.h
index 4fcca3d1e8cd3abff1210b9ad3df230f63af6c32..28352e86d441c9a66c621d223bed79e21673b189 100644
--- a/ProcessLib/LocalAssemblerInterface.h
+++ b/ProcessLib/LocalAssemblerInterface.h
@@ -92,6 +92,7 @@ public:
 
     /// Computes the flux in the point \c p_local_coords that is given in local
     /// coordinates using the values from \c local_x.
+    /// Fits to monolithic scheme.
     virtual Eigen::Vector3d getFlux(
         MathLib::Point3d const& /*p_local_coords*/,
         double const /*t*/,
@@ -100,6 +101,15 @@ public:
         return Eigen::Vector3d{};
     }
 
+    /// Fits to staggered scheme.
+    virtual Eigen::Vector3d getFlux(
+        MathLib::Point3d const& /*p_local_coords*/,
+        double const /*t*/,
+        std::vector<std::vector<double>> const& /*local_xs*/) const
+    {
+        return Eigen::Vector3d{};
+    }
+
 private:
     virtual void setInitialConditionsConcrete(
         std::vector<double> const& /*local_x*/, double const /*t*/)