diff --git a/ParameterLib/CoordinateSystem.h b/ParameterLib/CoordinateSystem.h
index 556a07fb27ac6b04ddd77f76e315895b910751f6..7a1f688ceee028fd015aae5b7d2dda8d8bdf5bbd 100644
--- a/ParameterLib/CoordinateSystem.h
+++ b/ParameterLib/CoordinateSystem.h
@@ -23,22 +23,33 @@ class SpatialPosition;
 
 namespace ParameterLib
 {
+/**
+ * \brief A local coordinate system used for tensor transformations.
+ *
+ * It offers a simple way for input of anisotropic tensors w.r.t. a coordinate
+ * system.
+ * The basis vectors form a transformation matrix \f$R = (e_0, e_1, e_2)\f$.
+ * For a given anisotropic tensor \f$A\f$ parameter with the corresponding
+ * \ref ogs_file_param__prj__parameters__parameter__use_local_coordinate_system
+ * the tensor is rotated according to the formula: \f$A' = R\cdot A\cdot R^T\f$.
+ *
+ * For computations in transverse isotropic material models, we can create a
+ * coordinate system with only one base, where the last base is explicitly
+ * given. The other bases are set as implicit and computed from the given base
+ * as follows:
+ *  - For a 2D coordinate system, the unit vector orthogonal to
+ *    the given base is used as the first base,
+ *  - For a 3D coordinate system, the given base vector, \c unit_direction,
+ *    is set as the third base,  \f${\vec e}_2\f$. An arbitrary unit vector
+ *    orthogonal to \f${\vec e}_2\f$ is selected as the second base
+ *    \f$e_1\f$, and the first  base \f${\vec e}_0\f$ is calculated as
+ *    \f${\vec e}_0 = {\vec e}_1 \times {\vec e}_2\f$.
+ */
 struct CoordinateSystem final
 {
     /**
-     * It is used to create a coordinate system with only one base, where the
-     * last base is explicitly given. The other bases are set as implicit and
-     * computed from the given base as follows:
-     *  - For a 2D coordinate system, the unit vector orthogonal to
-     *    the given base is used as the first base,
-     *  - For a 3D coordinate system, the given base vector, \c unit_direction,
-     *    is set as the third base,  \f${\vec e}_2\f$. An arbitrary unit vector
-     *    orthogonal to \f${\vec e}_2\f$ is selected as the second base
-     *    \f$e_1\f$, and the first  base \f${\vec e}_0\f$ is calculated as
-     *    \f${\vec e}_0 = {\vec e}_1 \times {\vec e}_2\f$.
-     *
-     * This type of coordinate system can be used for computations in transverse
-     * isotropic material models.
+     * It is used to create a local coordinate system with only one base, where
+     * the last base is explicitly given as \c unit_direction.
      *
      * @param unit_direction The specified unit direction.
      */
diff --git a/ParameterLib/CreateCoordinateSystem.cpp b/ParameterLib/CreateCoordinateSystem.cpp
index 083867c49dcb3ae74d9d103aa3bd90d68e03edf8..83ff60a9c5aa43fd001359d8ce880674b563ff0e 100644
--- a/ParameterLib/CreateCoordinateSystem.cpp
+++ b/ParameterLib/CreateCoordinateSystem.cpp
@@ -11,6 +11,8 @@
 
 #include "CreateCoordinateSystem.h"
 
+#include <string_view>
+
 #include "BaseLib/ConfigTree.h"
 #include "Parameter.h"
 #include "Utils.h"
@@ -20,6 +22,123 @@ namespace ParameterLib
 struct ParameterBase;
 struct CoordinateSystem;
 
+// Note: the function is used for parsing
+// 1. base1 for the case of an implicit base0.
+// 2. or base2.
+Parameter<double> const* parseBase1OrBase2(
+    BaseLib::ConfigTree const& config,
+    std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
+    int const expected_component_number,
+    std::string_view const base_tag_name)
+{
+    auto const base_parameter_name = config.getValue<std::string>();
+    auto const& basis_vector = ParameterLib::findParameter<double>(
+        base_parameter_name, parameters, 0 /* any dimension */);
+
+    int const component_number = basis_vector.getNumberOfGlobalComponents();
+    if (base_tag_name == "basis_vector_1" && component_number != 2)
+    {
+        OGS_FATAL(
+            "The case of implicit \"basis_vector_0\" and "
+            "explicit \"basis_vector_1\" is for a 2D coordinate system. The "
+            "parameter for \"basis_vector_1\", {:s}, must have "
+            "two components but it has {:d}. In addition, \"basis_vector_2\" "
+            "should not exist in this case.",
+            base_parameter_name, component_number);
+    }
+
+    if (component_number != expected_component_number)
+    {
+        OGS_FATAL(
+            "The read parameter `{:s}' for tag {:s} has the wrong number of "
+            "components ({:d} instead of {:d}).",
+            base_parameter_name, base_tag_name, component_number,
+            expected_component_number);
+    }
+
+    return &basis_vector;
+}
+
+void checkThirdBaseExistanceFor2D(BaseLib::ConfigTree const& config)
+{
+    auto const base2_config =
+        //! \ogs_file_param{prj__local_coordinate_system__basis_vector_2}
+        config.getConfigSubtreeOptional("basis_vector_2");
+    if (base2_config)
+    {
+        OGS_FATAL(
+            "The tag \"basis_vector_2\" is not needed for a 2D local "
+            "coordinate system.");
+    }
+}
+
+void confirmThirdBaseExplicit(BaseLib::ConfigTree const& config)
+{
+    auto const implicit_base2 =
+        //! \ogs_file_attr{prj__local_coordinate_system__basis_vector_2__implicit}
+        config.getConfigAttribute<bool>("implicit", false);
+    if (implicit_base2)
+    {
+        OGS_FATAL("basis_vector_2 must be explicit.");
+    }
+}
+
+std::optional<ParameterLib::CoordinateSystem>
+createCoordinateSystemWithImplicitBase(
+    BaseLib::ConfigTree const& config,
+    std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters)
+{
+    //! \ogs_file_param{prj__local_coordinate_system__basis_vector_1}
+    auto const& config_base1 = config.getConfigSubtree("basis_vector_1");
+
+    // Parse the second vectors.
+    auto const implicit_base1 =
+        //! \ogs_file_attr{prj__local_coordinate_system__basis_vector_1__implicit}
+        config_base1.getConfigAttribute<bool>("implicit", false);
+
+    if (!implicit_base1)
+    {
+        // For 2D problem.
+        // Only the following case is accepted:
+        // <basis_vector_0 implicit = false/>
+        // <basis_vector_1> [two-component parameter] </basis_vector_1>.
+        int const expected_component_number = 2;
+        auto const basis_vector_1 =
+            parseBase1OrBase2(config_base1, parameters,
+                              expected_component_number, "basis_vector_1");
+
+        checkThirdBaseExistanceFor2D(config);
+
+        return ParameterLib::CoordinateSystem(*basis_vector_1);
+    }
+
+    // For 3D problem.
+    // Only the following case is accepted:
+    // <basis_vector_0 implicit = false/>
+    // <basis_vector_1 implicit = false>.
+    // <basis_vector_2> [three-component parameter] </basis_vector_2>.
+
+    // Parse the third basis vector, e2, for the three dimensional system.
+    auto const config_base2 =
+        //! \ogs_file_param{prj__local_coordinate_system__basis_vector_2}
+        config.getConfigSubtreeOptional("basis_vector_2");
+    if (!config_base2)
+    {
+        OGS_FATAL(
+            "Both \"basis_vector_0\" and \"basis_vector_1\" are implicit but "
+            "\"basis_vector_2\" does not exist. If 2D coordinate system is "
+            "considered, please change \"basis_vector_1\" to explicit. If 3D "
+            "coordinate system is considered, please add \"basis_vector_2\".");
+    }
+
+    confirmThirdBaseExplicit(*config_base2);
+
+    int const expected_component_number = 3;
+    auto const basis_vector_2 = parseBase1OrBase2(
+        *config_base2, parameters, expected_component_number, "basis_vector_2");
+    return ParameterLib::CoordinateSystem(*basis_vector_2);
+}
+
 std::optional<ParameterLib::CoordinateSystem> createCoordinateSystem(
     std::optional<BaseLib::ConfigTree> const& config,
     std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters)
@@ -29,51 +148,71 @@ std::optional<ParameterLib::CoordinateSystem> createCoordinateSystem(
         return {};
     }
 
-    DBUG("Reading coordinate system configuration.");
-
     //
     // Fetch the first basis vector; its length defines the dimension.
     //
+    //! \ogs_file_param{prj__local_coordinate_system__basis_vector_0}
+    auto const& config_base0 = config->getConfigSubtree("basis_vector_0");
+    auto const implicit_base0 =
+        //! \ogs_file_attr{prj__local_coordinate_system__basis_vector_0__implicit}
+        config_base0.getConfigAttribute<bool>("implicit", false);
+
+    // base0 and base1 can be implicit. If base0 is implicit, check whether
+    // base1 is implicit.
+    // If base1 is explicit, create a 2D system if its components is 2 or quit
+    // if its components is not equal to 2.
+    // Otherwise, read base2, create a 3D system if its components is 3 or quit
+    // if its components is not equal to 3.
+    if (implicit_base0)
+    {
+        return createCoordinateSystemWithImplicitBase(*config, parameters);
+    }
+
+    auto const base0_name = config_base0.getValue<std::string>();
     auto const& basis_vector_0 = ParameterLib::findParameter<double>(
-        *config,
-        //! \ogs_file_param_special{prj__local_coordinate_system__basis_vector_0}
-        "basis_vector_0", parameters, 0 /* any dimension */);
+        base0_name, parameters, 0 /* any dimension */);
     int const dimension = basis_vector_0.getNumberOfGlobalComponents();
-
     // check dimension
     if (dimension != 2 && dimension != 3)
     {
         OGS_FATAL(
             "Basis vector parameter '{:s}' must have two or three components, "
             "but it has {:d}.",
-            basis_vector_0.name, dimension);
+            base0_name, dimension);
     }
 
-    //
-    // Fetch the second basis vector, which must be of the same dimension as the
-    // first one.
-    //
-    auto const& basis_vector_1 = ParameterLib::findParameter<double>(
-        *config,
-        //! \ogs_file_param_special{prj__local_coordinate_system__basis_vector_1}
-        "basis_vector_1", parameters, dimension);
+    // Fetch the second basis vector.
+    //! \ogs_file_param{prj__local_coordinate_system__basis_vector_1}
+    auto const& config_base1 = config->getConfigSubtree("basis_vector_1");
+    auto const implicit_base1 =
+        //! \ogs_file_attr{prj__local_coordinate_system__basis_vector_1__implicit}
+        config_base1.getConfigAttribute<bool>("implicit", false);
+    if (implicit_base1)
+    {
+        OGS_FATAL(
+            "Since basis_vector_0 is explicitly defined, basis_vector_1"
+            " must be explicit as well.");
+    }
+    auto const base1_name = config_base1.getValue<std::string>();
+    auto const& basis_vector_1 =
+        ParameterLib::findParameter<double>(base1_name, parameters, dimension);
 
-    //
-    // For two dimensions, we are done; construct coordinate system;
-    //
     if (dimension == 2)
     {
+        checkThirdBaseExistanceFor2D(*config);
         return ParameterLib::CoordinateSystem{basis_vector_0, basis_vector_1};
     }
 
-    //
-    // Parse the third vector, for three dimensions.
-    //
-    auto const& basis_vector_2 = ParameterLib::findParameter<double>(
-        *config,
-        //! \ogs_file_param_special{prj__local_coordinate_system__basis_vector_2}
-        "basis_vector_2", parameters, dimension);
+    // Parse the third basis vector, e2, for the three dimensional system.
+    //! \ogs_file_param{prj__local_coordinate_system__basis_vector_2}
+    auto const& config_base2 = config->getConfigSubtree("basis_vector_2");
+    confirmThirdBaseExplicit(config_base2);
+
+    int const expected_component_number = 3;
+    auto const basis_vector_2 = parseBase1OrBase2(
+        config_base2, parameters, expected_component_number, "basis_vector_2");
+
     return ParameterLib::CoordinateSystem{basis_vector_0, basis_vector_1,
-                                          basis_vector_2};
+                                          *basis_vector_2};
 }
 }  // namespace ParameterLib