diff --git a/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/NonuniformDirichlet/c_NonuniformDirichlet.md b/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/NonuniformDirichlet/c_NonuniformDirichlet.md
new file mode 100644
index 0000000000000000000000000000000000000000..a4df55e6ec1007021690f91c9933f42783d21ff5
--- /dev/null
+++ b/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/NonuniformDirichlet/c_NonuniformDirichlet.md
@@ -0,0 +1,2 @@
+Declares a Dirichlet boundary condition that is non-uniform in space.
+The values are read from the given boundary mesh.
diff --git a/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/NonuniformDirichlet/t_field_name.md b/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/NonuniformDirichlet/t_field_name.md
new file mode 100644
index 0000000000000000000000000000000000000000..fc5aead79e2a9cd6e2b973505bc4c317288903e4
--- /dev/null
+++ b/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/NonuniformDirichlet/t_field_name.md
@@ -0,0 +1,3 @@
+This specifies a nodal field defined on the surface mesh (see the \c mesh
+parameter of the nonuniform Dirichlet BC) and the values used for the boundary
+condition.
diff --git a/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/NonuniformDirichlet/t_mesh.md b/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/NonuniformDirichlet/t_mesh.md
new file mode 100644
index 0000000000000000000000000000000000000000..b448b3494b3b8e6e94b50a58ec0e10733171e06e
--- /dev/null
+++ b/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/NonuniformDirichlet/t_mesh.md
@@ -0,0 +1,8 @@
+Path to the surface mesh vtu file.
+
+The surface mesh must contain a nodal integer-valued field (unsigned 64bit)
+named \c OriginalSubsurfaceNodeIDs. That field establishes the mapping between
+the nodes of the surface mesh to some notes in the bulk mesh.
+\warning It is not checked if the surface mesh and the bulk mesh correspond to each
+other; in particular it is not checked if surface and bulk nodes coincide and if
+surface elements coincide with the faces of bulk elements.
diff --git a/ProcessLib/BoundaryCondition/BoundaryCondition.cpp b/ProcessLib/BoundaryCondition/BoundaryCondition.cpp
index 55edb6fda627ceb6b2ce6162d397d9c3d9c30840..5ad6afe6310d0516f691b6796f32cf6ba9cb3c2b 100644
--- a/ProcessLib/BoundaryCondition/BoundaryCondition.cpp
+++ b/ProcessLib/BoundaryCondition/BoundaryCondition.cpp
@@ -15,6 +15,7 @@
 #include "MeshGeoToolsLib/MeshNodeSearcher.h"
 #include "MeshGeoToolsLib/SearchLength.h"
 #include "NeumannBoundaryCondition.h"
+#include "NonuniformDirichletBoundaryCondition.h"
 #include "NonuniformNeumannBoundaryCondition.h"
 #include "PressureBoundaryCondition.h"
 #include "RobinBoundaryCondition.h"
@@ -50,6 +51,11 @@ BoundaryConditionBuilder::createBoundaryCondition(
                     config, dof_table, mesh, variable_id,
                     integration_order, shapefunction_order, parameters);
     }
+    if (type == "NonuniformDirichlet")
+    {
+        return createNonuniformDirichletBoundaryCondition(config, dof_table,
+                                                          mesh, variable_id);
+    }
     if (type == "NonuniformNeumann")
     {
         return createNonuniformNeumannBoundaryCondition(
@@ -175,6 +181,16 @@ BoundaryConditionBuilder::createRobinBoundaryCondition(
         parameters);
 }
 
+std::unique_ptr<BoundaryCondition>
+BoundaryConditionBuilder::createNonuniformDirichletBoundaryCondition(
+    const BoundaryConditionConfig& config,
+    const NumLib::LocalToGlobalIndexMap& dof_table, const MeshLib::Mesh& mesh,
+    const int variable_id)
+{
+    return ProcessLib::createNonuniformDirichletBoundaryCondition(
+        config.config, dof_table, variable_id, *config.component_id, mesh);
+}
+
 std::unique_ptr<BoundaryCondition>
 BoundaryConditionBuilder::createNonuniformNeumannBoundaryCondition(
     const BoundaryConditionConfig& config,
diff --git a/ProcessLib/BoundaryCondition/BoundaryCondition.h b/ProcessLib/BoundaryCondition/BoundaryCondition.h
index 8c6a28a1b0b183185cf3abddf4938c200c557360..08c89fb5386f131145c0cb293c7ab8ec76fce8bd 100644
--- a/ProcessLib/BoundaryCondition/BoundaryCondition.h
+++ b/ProcessLib/BoundaryCondition/BoundaryCondition.h
@@ -62,8 +62,6 @@ public:
         // Therefore there is nothing to do here.
     }
 
-    virtual void preTimestep(const double /*t*/) {}
-
     virtual ~BoundaryCondition() = default;
 };
 
@@ -107,6 +105,12 @@ protected:
         const std::vector<std::unique_ptr<ProcessLib::ParameterBase>>&
             parameters);
 
+    virtual std::unique_ptr<BoundaryCondition>
+    createNonuniformDirichletBoundaryCondition(
+        const BoundaryConditionConfig& config,
+        const NumLib::LocalToGlobalIndexMap& dof_table,
+        const MeshLib::Mesh& mesh, const int variable_id);
+
     virtual std::unique_ptr<BoundaryCondition>
     createNonuniformNeumannBoundaryCondition(
         const BoundaryConditionConfig& config,
diff --git a/ProcessLib/BoundaryCondition/BoundaryConditionCollection.cpp b/ProcessLib/BoundaryCondition/BoundaryConditionCollection.cpp
index caedc8e305d3b4f868d60cb49c256a4fa7a8ab1c..5c3790dc09b34d05a5e126d9f96917b4b4eca971 100644
--- a/ProcessLib/BoundaryCondition/BoundaryConditionCollection.cpp
+++ b/ProcessLib/BoundaryCondition/BoundaryConditionCollection.cpp
@@ -43,10 +43,4 @@ void BoundaryConditionCollection::addBCsForProcessVariables(
     // object if needed.
     _dirichlet_bcs.resize(_boundary_conditions.size());
 }
-
-void BoundaryConditionCollection::preTimestep(const double t)
-{
-    for (auto& bc : _boundary_conditions)
-        bc->preTimestep(t);
-}
 }
diff --git a/ProcessLib/BoundaryCondition/BoundaryConditionCollection.h b/ProcessLib/BoundaryCondition/BoundaryConditionCollection.h
index 827e01ba96b7ac2586ab7142bb12590c9f91155d..fa4e4c5927bffe97335a763dcd8c94d8e811ef5f 100644
--- a/ProcessLib/BoundaryCondition/BoundaryConditionCollection.h
+++ b/ProcessLib/BoundaryCondition/BoundaryConditionCollection.h
@@ -44,8 +44,6 @@ public:
         NumLib::LocalToGlobalIndexMap const& dof_table,
         unsigned const integration_order);
 
-    void preTimestep(const double t);
-
 private:
     mutable std::vector<NumLib::IndexValueVector<GlobalIndexType>> _dirichlet_bcs;
     std::vector<std::unique_ptr<BoundaryCondition>> _boundary_conditions;
diff --git a/ProcessLib/BoundaryCondition/DirichletBoundaryCondition.cpp b/ProcessLib/BoundaryCondition/DirichletBoundaryCondition.cpp
index 5b7f98728da2b6dce53699c1ed639a61f3b3d4fc..15dc308530f19f9a942e180221789ffc48ace44c 100644
--- a/ProcessLib/BoundaryCondition/DirichletBoundaryCondition.cpp
+++ b/ProcessLib/BoundaryCondition/DirichletBoundaryCondition.cpp
@@ -16,21 +16,9 @@
 
 namespace ProcessLib
 {
-void DirichletBoundaryCondition::preTimestep(const double /*t*/)
-{
-    if (_parameter.isTimeDependent())
-        _already_computed = false;
-}
-
 void DirichletBoundaryCondition::getEssentialBCValues(
     const double t, NumLib::IndexValueVector<GlobalIndexType>& bc_values) const
 {
-    // TODO: Reenable when fixed ;)
-    //if (_already_computed)
-        //return;
-
-    _already_computed = true;
-
     SpatialPosition pos;
 
     bc_values.ids.clear();
diff --git a/ProcessLib/BoundaryCondition/DirichletBoundaryCondition.h b/ProcessLib/BoundaryCondition/DirichletBoundaryCondition.h
index 0654e5605ea6884a3639f369aacdd3c937a3b344..f4d33558bff3cc231adf4c82b6bbd959b84269fe 100644
--- a/ProcessLib/BoundaryCondition/DirichletBoundaryCondition.h
+++ b/ProcessLib/BoundaryCondition/DirichletBoundaryCondition.h
@@ -49,8 +49,6 @@ public:
         }
     }
 
-    void preTimestep(const double t) override;
-
     void getEssentialBCValues(
         const double t,
         NumLib::IndexValueVector<GlobalIndexType>& bc_values) const override;
@@ -63,7 +61,6 @@ private:
     std::size_t const _mesh_id;
     int const _variable_id;
     int const _component_id;
-    mutable bool _already_computed = false;
 };
 
 std::unique_ptr<DirichletBoundaryCondition> createDirichletBoundaryCondition(
diff --git a/ProcessLib/BoundaryCondition/NonuniformDirichletBoundaryCondition.cpp b/ProcessLib/BoundaryCondition/NonuniformDirichletBoundaryCondition.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dc548e78806a40e6c73186f20957601e3417cda3
--- /dev/null
+++ b/ProcessLib/BoundaryCondition/NonuniformDirichletBoundaryCondition.cpp
@@ -0,0 +1,94 @@
+/**
+ * \file
+ *
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#include "NonuniformDirichletBoundaryCondition.h"
+
+#include "MeshLib/IO/readMeshFromFile.h"
+#include "ProcessLib/Utils/ProcessUtils.h"
+
+namespace ProcessLib
+{
+std::unique_ptr<NonuniformDirichletBoundaryCondition>
+createNonuniformDirichletBoundaryCondition(
+    BaseLib::ConfigTree const& config,
+    NumLib::LocalToGlobalIndexMap const& dof_table, int const variable_id,
+    int const component_id, MeshLib::Mesh const& bulk_mesh)
+{
+    DBUG("Constructing NonuniformDirichlet BC from config.");
+    //! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__type}
+    config.checkConfigParameter("type", "NonuniformDirichlet");
+
+    // TODO handle paths correctly
+    //! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__NonuniformDirichlet__mesh}
+    auto const mesh_file = config.getConfigParameter<std::string>("mesh");
+
+    std::unique_ptr<MeshLib::Mesh> boundary_mesh(
+        MeshLib::IO::readMeshFromFile(mesh_file));
+
+    if (!boundary_mesh)
+    {
+        OGS_FATAL("Error reading mesh `%s'", mesh_file.c_str());
+    }
+
+    // The axial symmetry is not used in the Dirichlet BC but kept here for
+    // consistency.
+    //
+    // Surface mesh and bulk mesh must have equal axial symmetry flags!
+    boundary_mesh->setAxiallySymmetric(bulk_mesh.isAxiallySymmetric());
+
+    // TODO finally use ProcessLib::Parameter here
+    auto const field_name =
+        //! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__NonuniformDirichlet__field_name}
+        config.getConfigParameter<std::string>("field_name");
+
+    auto const* const property =
+        boundary_mesh->getProperties().getPropertyVector<double>(field_name);
+
+    if (!property)
+    {
+        OGS_FATAL("A property with name `%s' does not exist in `%s'.",
+                  field_name.c_str(), mesh_file.c_str());
+    }
+
+    if (property->getMeshItemType() != MeshLib::MeshItemType::Node)
+    {
+        OGS_FATAL(
+            "Only nodal fields are supported for non-uniform fields. Field "
+            "`%s' is not nodal.",
+            field_name.c_str());
+    }
+
+    if (property->getNumberOfComponents() != 1)
+    {
+        OGS_FATAL("`%s' is not a one-component field.", field_name.c_str());
+    }
+
+    std::string const mapping_to_bulk_nodes_property =
+        "OriginalSubsurfaceNodeIDs";
+    auto const* const mapping_to_bulk_nodes =
+        boundary_mesh->getProperties().getPropertyVector<std::size_t>(
+            mapping_to_bulk_nodes_property);
+
+    if (!(mapping_to_bulk_nodes && mapping_to_bulk_nodes->getMeshItemType() ==
+                                       MeshLib::MeshItemType::Node) &&
+        mapping_to_bulk_nodes->getNumberOfComponents() == 1)
+    {
+        OGS_FATAL("Field `%s' is not set up properly.",
+                  mapping_to_bulk_nodes_property.c_str());
+    }
+
+    return std::make_unique<NonuniformDirichletBoundaryCondition>(
+        // bulk_mesh.getDimension(),
+        std::move(boundary_mesh), *property, bulk_mesh.getID(),
+        *mapping_to_bulk_nodes, dof_table, variable_id, component_id);
+}
+
+}  // ProcessLib
diff --git a/ProcessLib/BoundaryCondition/NonuniformDirichletBoundaryCondition.h b/ProcessLib/BoundaryCondition/NonuniformDirichletBoundaryCondition.h
new file mode 100644
index 0000000000000000000000000000000000000000..c08eb6b62d75447a179f88a2913010d77f547048
--- /dev/null
+++ b/ProcessLib/BoundaryCondition/NonuniformDirichletBoundaryCondition.h
@@ -0,0 +1,109 @@
+/**
+ * \file
+ *
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#pragma once
+
+#include "BoundaryCondition.h"
+
+#include "MeshLib/PropertyVector.h"
+#include "NumLib/DOF/DOFTableUtil.h"
+#include "NumLib/DOF/LocalToGlobalIndexMap.h"
+#include "NumLib/IndexValueVector.h"
+#include "ProcessLib/Parameter/Parameter.h"
+#include "ProcessLib/Utils/ProcessUtils.h"
+
+namespace ProcessLib
+{
+class NonuniformDirichletBoundaryCondition final : public BoundaryCondition
+{
+public:
+    NonuniformDirichletBoundaryCondition(
+        // int const bulk_mesh_dimension,
+        std::unique_ptr<MeshLib::Mesh>
+            boundary_mesh,
+        MeshLib::PropertyVector<double> const& values,
+        std::size_t const bulk_mesh_id,
+        MeshLib::PropertyVector<std::size_t> const& mapping_to_bulk_nodes,
+        NumLib::LocalToGlobalIndexMap const& dof_table_bulk,
+        int const variable_id_bulk,
+        int const component_id_bulk)
+        : _bulk_mesh_id(bulk_mesh_id),
+          _values(values),
+          _boundary_mesh(std::move(boundary_mesh)),
+          _mapping_to_bulk_nodes(mapping_to_bulk_nodes),
+          _dof_table_bulk(dof_table_bulk),
+          _variable_id_bulk(variable_id_bulk),
+          _component_id_bulk(component_id_bulk)
+    {
+        if (_variable_id_bulk >=
+                static_cast<int>(_dof_table_bulk.getNumberOfVariables()) ||
+            _component_id_bulk >= _dof_table_bulk.getNumberOfVariableComponents(
+                                      _variable_id_bulk))
+        {
+            OGS_FATAL(
+                "Variable id or component id too high. Actual values: (%d, "
+                "%d), "
+                "maximum values: (%d, %d).",
+                _variable_id_bulk, _component_id_bulk,
+                _dof_table_bulk.getNumberOfVariables(),
+                _dof_table_bulk.getNumberOfVariableComponents(
+                    _variable_id_bulk));
+        }
+    }
+
+    void getEssentialBCValues(
+        const double /*t*/,
+        NumLib::IndexValueVector<GlobalIndexType>& bc_values) const override
+    {
+        SpatialPosition pos;
+
+        bc_values.ids.clear();
+        bc_values.values.clear();
+
+        // Convert mesh node ids to global index for the given component.
+        bc_values.ids.reserve(_values.size());
+        bc_values.values.reserve(_values.size());
+
+        // Map boundary dof indices to bulk dof indices and the corresponding
+        // values.
+        for (std::size_t i = 0; i < _boundary_mesh->getNumberOfNodes(); ++i)
+        {
+            auto const bulk_node_id = _mapping_to_bulk_nodes.getComponent(i, 0);
+
+            MeshLib::Location const l{
+                _bulk_mesh_id, MeshLib::MeshItemType::Node, bulk_node_id};
+
+            auto const global_index = _dof_table_bulk.getGlobalIndex(
+                l, _variable_id_bulk, _component_id_bulk);
+            assert(global_index != NumLib::MeshComponentMap::nop);
+
+            bc_values.ids.push_back(global_index);
+            bc_values.values.push_back(_values.getComponent(i, 0));
+        }
+    }
+
+private:
+    std::size_t _bulk_mesh_id;
+    MeshLib::PropertyVector<double> const& _values;
+    std::unique_ptr<MeshLib::Mesh> _boundary_mesh;
+    MeshLib::PropertyVector<std::size_t> const& _mapping_to_bulk_nodes;
+    NumLib::LocalToGlobalIndexMap const& _dof_table_bulk;
+    int const _variable_id_bulk;
+    int const _component_id_bulk;
+};
+
+std::unique_ptr<NonuniformDirichletBoundaryCondition>
+createNonuniformDirichletBoundaryCondition(
+    BaseLib::ConfigTree const& config,
+    NumLib::LocalToGlobalIndexMap const& dof_table, int const variable_id,
+    int const component_id, const MeshLib::Mesh& bulk_mesh);
+
+}  // ProcessLib
diff --git a/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryCondition.cpp b/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryCondition.cpp
index dc8c456eed4ad4ce0ef356722eec77bbd859e03e..614246bfde5bec956f6eec4dcb2fead85781fc80 100644
--- a/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryCondition.cpp
+++ b/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryCondition.cpp
@@ -67,7 +67,7 @@ createNonuniformNeumannBoundaryCondition(
         OGS_FATAL("`%s' is not a one-component field.", field_name.c_str());
     }
 
-    std::string mapping_to_bulk_nodes_property = "OriginalSubsurfaceNodeIDs";
+    std::string const mapping_to_bulk_nodes_property = "OriginalSubsurfaceNodeIDs";
     auto const* const mapping_to_bulk_nodes =
         boundary_mesh->getProperties().getPropertyVector<std::size_t>(
             mapping_to_bulk_nodes_property);
diff --git a/ProcessLib/GroundwaterFlow/Tests.cmake b/ProcessLib/GroundwaterFlow/Tests.cmake
index a155dc97a64482a861f099572a826b859163e230..ff7582f71d535164c9fc15520b423b71f819a433 100644
--- a/ProcessLib/GroundwaterFlow/Tests.cmake
+++ b/ProcessLib/GroundwaterFlow/Tests.cmake
@@ -585,3 +585,15 @@ AddTest(
     DIFF_DATA
     inhomogeneous_permeability.vtu neumann_nonuniform_pcs_0_ts_1_t_1.000000.vtu mass_flux_ref mass_flux
 )
+
+AddTest(
+    NAME GroundWaterFlowProcess_Dirichlet_nonuniform
+    PATH Elliptic/nonuniform_bc_Groundwaterflow
+    EXECUTABLE ogs
+    EXECUTABLE_ARGS dirichlet_nonuniform.prj
+    TESTER vtkdiff
+    REQUIREMENTS NOT OGS_USE_MPI
+    ABSTOL 1e-14 RELTOL 1e-16
+    DIFF_DATA
+    expected_dirichlet_nonuniform_pcs_0_ts_1_t_1.000000.vtu dirichlet_nonuniform_pcs_0_ts_1_t_1.000000.vtu pressure pressure
+)
diff --git a/ProcessLib/Process.cpp b/ProcessLib/Process.cpp
index bb23d059b4356b074bf79e0dce74f52512577a2e..afe758b7ebb500884aa67674dcffebbbb75dd260 100644
--- a/ProcessLib/Process.cpp
+++ b/ProcessLib/Process.cpp
@@ -245,7 +245,6 @@ void Process::preTimestep(GlobalVector const& x, const double t,
 
     MathLib::LinAlg::setLocalAccessibleVector(x);
     preTimestepConcreteProcess(x, t, delta_t);
-    _boundary_conditions.preTimestep(t);
 }
 
 void Process::postTimestep(GlobalVector const& x)
diff --git a/Tests/Data b/Tests/Data
index 094bd3a2516375c774efd69c99f36404120bfc73..accf02eaaf1c4c0581f1a4aeb91fc86e714a2966 160000
--- a/Tests/Data
+++ b/Tests/Data
@@ -1 +1 @@
-Subproject commit 094bd3a2516375c774efd69c99f36404120bfc73
+Subproject commit accf02eaaf1c4c0581f1a4aeb91fc86e714a2966