diff --git a/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp b/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp
index 7555f4b8f5cba0046de1d62e65b287a69ac31047..9fc76aac8b3bd320a5dd5a88ba8a98dc582a036a 100644
--- a/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp
+++ b/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp
@@ -17,6 +17,7 @@
 #include <limits>
 #include <iomanip>
 #include <cstdio>  // for binary output
+#include <numeric>
 
 #include <logog/include/logog.hpp>
 
@@ -24,7 +25,6 @@
 
 #include "MeshLib/IO/VtkIO/VtuInterface.h"
 
-#include "MeshLib/Node.h"
 #include "MeshLib/Elements/Element.h"
 
 namespace ApplicationUtils
@@ -84,106 +84,173 @@ void NodeWiseMeshPartitioner::readMetisData(const std::string& file_name_base)
     std::remove(fname_eparts.c_str());
 }
 
-void NodeWiseMeshPartitioner::partitionByMETIS(
-    const bool is_mixed_high_order_linear_elems)
+void NodeWiseMeshPartitioner::findNonGhostNodesInPartition(
+    std::size_t const part_id,
+    const bool is_mixed_high_order_linear_elems,
+    std::vector<MeshLib::Node*>& extra_nodes)
 {
     std::vector<MeshLib::Node*> const& nodes = _mesh->getNodes();
-    for (std::size_t part_id = 0; part_id < _partitions.size(); part_id++)
+    auto& partition = _partitions[part_id];
+    // -- Extra nodes for high order elements
+    for (std::size_t i = 0; i < _mesh->getNumberOfNodes(); i++)
     {
-        auto& partition = _partitions[part_id];
+        if (_nodes_partition_ids[i] == part_id)
+        {
+            splitOfHigherOrderNode(nodes, is_mixed_high_order_linear_elems,
+                                   i, partition.nodes, extra_nodes);
+        }
+    }
+    partition.number_of_non_ghost_base_nodes = partition.nodes.size();
+    partition.number_of_non_ghost_nodes =
+        partition.number_of_non_ghost_base_nodes + extra_nodes.size();
+}
 
-        INFO("Processing partition: %d", part_id);
+void NodeWiseMeshPartitioner::findElementsInPartition(
+    std::size_t const part_id, const bool is_mixed_high_order_linear_elems)
+{
+    auto& partition = _partitions[part_id];
+    std::vector<MeshLib::Element*> const& elements = _mesh->getElements();
+    std::vector<bool> _is_regular_element(elements.size(), false);
+
+    for (std::size_t elem_id = 0; elem_id < elements.size(); elem_id++)
+    {
+        const auto* elem = elements[elem_id];
+        if (_is_regular_element[elem_id])
+            continue;
 
-        // Find non-ghost nodes in this partition
-        // -- Extra nodes for high order elements
-        std::vector<MeshLib::Node*> extra_nodes;
-        for (std::size_t i = 0; i < _mesh->getNumberOfNodes(); i++)
+        std::size_t non_ghost_node_number = 0;
+        for (unsigned i = 0; i < elem->getNumberOfNodes(); i++)
         {
-            if (_nodes_partition_ids[i] == part_id)
+            if (_nodes_partition_ids[elem->getNodeIndex(i)] == part_id)
             {
-                if (is_mixed_high_order_linear_elems)
-                { // TODO: Test it once there is a case
-                    if (i < _mesh->getNumberOfBaseNodes())
-                        partition.nodes.push_back(nodes[i]);
-                    else
-                        extra_nodes.push_back(nodes[i]);
-                }
-                else
-                {
-                    partition.nodes.push_back(nodes[i]);
-                }
+                non_ghost_node_number++;
             }
         }
-        partition.number_of_non_ghost_base_nodes = partition.nodes.size();
-        partition.number_of_non_ghost_nodes =
-            partition.number_of_non_ghost_base_nodes + extra_nodes.size();
 
-        // Find elements that belong to this partition
-        std::vector<MeshLib::Element*> const& elements = _mesh->getElements();
-        for (std::size_t elem_id = 0; elem_id < elements.size(); elem_id++)
-        {
-            const auto* elem = elements[elem_id];
-            if (_elements_status[elem_id])
-                continue;
+        if (non_ghost_node_number == 0)
+            continue;
 
-            std::size_t non_ghost_node_number = 0;
-            for (unsigned i = 0; i < elem->getNumberOfNodes(); i++)
-            {
-                if (_nodes_partition_ids[elem->getNodeIndex(i)] == part_id)
-                {
-                    non_ghost_node_number++;
-                }
-            }
+        if (non_ghost_node_number == elem->getNumberOfNodes())
+        {
+            partition.regular_elements.push_back(elem);
+            _is_regular_element[elem_id] = true;
+        }
+        else
+        {
+            partition.ghost_elements.push_back(elem);
+        }
+    }
+}
 
-            if (non_ghost_node_number == 0)
+void NodeWiseMeshPartitioner::findGhostNodesInPartition(
+    std::size_t const part_id,
+    const bool is_mixed_high_order_linear_elems,
+    std::vector<MeshLib::Node*>& extra_nodes)
+{
+    auto& partition = _partitions[part_id];
+    std::vector<MeshLib::Node*> const& nodes = _mesh->getNodes();
+    std::vector<bool> nodes_reserved(_mesh->getNumberOfNodes(), false);
+    for (const auto* ghost_elem : partition.ghost_elements)
+    {
+        for (unsigned i = 0; i < ghost_elem->getNumberOfNodes(); i++)
+        {
+            const unsigned node_id = ghost_elem->getNodeIndex(i);
+            if (nodes_reserved[node_id])
                 continue;
 
-            if (non_ghost_node_number == elem->getNumberOfNodes())
-            {
-                partition.regular_elements.push_back(elem);
-                _elements_status[elem_id] = true;
-            }
-            else
+            if (_nodes_partition_ids[node_id] != part_id)
             {
-                partition.ghost_elements.push_back(elem);
+                splitOfHigherOrderNode(nodes, is_mixed_high_order_linear_elems,
+                                       node_id, partition.nodes, extra_nodes);
+                nodes_reserved[node_id] = true;
             }
         }
+    }
+}
 
-        // Find the ghost nodes of this partition
-        std::vector<bool> nodes_reserved(_mesh->getNumberOfNodes(), false);
-        for (const auto* ghost_elem : partition.ghost_elements)
-        {
-            for (unsigned i = 0; i < ghost_elem->getNumberOfNodes(); i++)
-            {
-                const unsigned node_id = ghost_elem->getNodeIndex(i);
-                if (nodes_reserved[node_id])
-                    continue;
-
-                if (_nodes_partition_ids[node_id] != part_id)
-                {
-                    if (is_mixed_high_order_linear_elems)
-                    {
-                        if (node_id < _mesh->getNumberOfBaseNodes())
-                            partition.nodes.push_back(nodes[node_id]);
-                        else
-                            extra_nodes.push_back(nodes[node_id]);
-                    }
-                    else
-                    {
-                        partition.nodes.push_back(nodes[node_id]);
-                    }
-                    nodes_reserved[node_id] = true;
-                }
-            }
-        }
-        partition.number_of_base_nodes = partition.nodes.size();
+void NodeWiseMeshPartitioner::splitOfHigherOrderNode(
+    std::vector<MeshLib::Node*> const& nodes,
+    bool const is_mixed_high_order_linear_elems,
+    unsigned const node_id,
+    std::vector<MeshLib::Node*>& base_nodes,
+    std::vector<MeshLib::Node*>& extra_nodes)
+{
+    if (is_mixed_high_order_linear_elems)
+    {
+        if (node_id < _mesh->getNumberOfBaseNodes())
+            base_nodes.push_back(nodes[node_id]);
+        else
+            extra_nodes.push_back(nodes[node_id]);
+    }
+    else
+    {
+        base_nodes.push_back(nodes[node_id]);
+    }
+}
 
-        if (is_mixed_high_order_linear_elems)
-            partition.nodes.insert(partition.nodes.end(), extra_nodes.begin(),
-                                   extra_nodes.end());
+void NodeWiseMeshPartitioner::processPartition(std::size_t const part_id,
+    const bool is_mixed_high_order_linear_elems)
+{
+    std::vector<MeshLib::Node*> extra_nodes;
+    findNonGhostNodesInPartition(part_id, is_mixed_high_order_linear_elems,
+                                 extra_nodes);
+
+    findElementsInPartition(part_id, is_mixed_high_order_linear_elems);
+    findGhostNodesInPartition(part_id, is_mixed_high_order_linear_elems,
+                              extra_nodes);
+    auto& partition = _partitions[part_id];
+    partition.number_of_base_nodes = partition.nodes.size();
+
+    if (is_mixed_high_order_linear_elems)
+        partition.nodes.insert(partition.nodes.end(), extra_nodes.begin(),
+                               extra_nodes.end());
+}
+
+void NodeWiseMeshPartitioner::processProperties()
+{
+    std::size_t const total_number_of_tuples =
+        std::accumulate(std::begin(_partitions), std::end(_partitions), 0,
+                        [](std::size_t const sum, Partition const& p) {
+                            return sum + p.nodes.size();
+                        });
+
+    INFO("total number of tuples after partitioning: %d ",
+         total_number_of_tuples);
+    // 1 create new PV
+    // 2 resize the PV with total_number_of_tuples
+    // 3 copy the values according to the partition info
+    auto const& original_properties(_mesh->getProperties());
+    auto property_names = original_properties.getPropertyVectorNames();
+    for (auto const& name : property_names)
+    {
+        bool success =
+            copyPropertyVector<double>(name, total_number_of_tuples) ||
+            copyPropertyVector<float>(name, total_number_of_tuples) ||
+            copyPropertyVector<int>(name, total_number_of_tuples) ||
+            copyPropertyVector<long>(name, total_number_of_tuples) ||
+            copyPropertyVector<unsigned>(name, total_number_of_tuples) ||
+            copyPropertyVector<unsigned long>(name, total_number_of_tuples) ||
+            copyPropertyVector<std::size_t>(name, total_number_of_tuples);
+        if (!success)
+            WARN(
+                "processProperties: Could not create partitioned "
+                "PropertyVector '%s'.",
+                name.c_str());
+    }
+}
+
+void NodeWiseMeshPartitioner::partitionByMETIS(
+    const bool is_mixed_high_order_linear_elems)
+{
+    for (std::size_t part_id = 0; part_id < _partitions.size(); part_id++)
+    {
+        INFO("Processing partition: %d", part_id);
+        processPartition(part_id, is_mixed_high_order_linear_elems);
     }
 
     renumberNodeIndices(is_mixed_high_order_linear_elems);
+
+    processProperties();
 }
 
 void NodeWiseMeshPartitioner::renumberNodeIndices(
@@ -262,6 +329,57 @@ NodeWiseMeshPartitioner::getNumberOfIntegerVariablesOfElements(
     return nmb_element_idxs;
 }
 
+void NodeWiseMeshPartitioner::writePropertiesBinary(
+    const std::string& file_name_base) const
+{
+    auto const& property_names(_partitioned_properties.getPropertyVectorNames());
+    if (property_names.empty())
+        return;
+    const std::string fname_cfg = file_name_base +
+                                  "_partitioned_properties_cfg" +
+                                  std::to_string(_npartitions) + ".bin";
+    std::ofstream out(fname_cfg.c_str(), std::ios::binary | std::ios::out);
+
+    const std::string fname_val = file_name_base +
+                                  "_partitioned_properties_val" +
+                                  std::to_string(_npartitions) + ".bin";
+    std::ofstream out_val(fname_val.c_str(), std::ios::binary | std::ios::out);
+
+    std::size_t number_of_properties(property_names.size());
+    out.write(reinterpret_cast<char*>(&number_of_properties),
+              sizeof(number_of_properties));
+    for (auto const& name : property_names)
+    {
+        bool success =
+            writePropertyVectorBinary<double>(name, out_val, out) ||
+            writePropertyVectorBinary<float>(name, out_val, out) ||
+            writePropertyVectorBinary<int>(name, out_val, out) ||
+            writePropertyVectorBinary<long>(name, out_val, out) ||
+            writePropertyVectorBinary<unsigned>(name, out_val, out) ||
+            writePropertyVectorBinary<unsigned long>(name, out_val, out) ||
+            writePropertyVectorBinary<std::size_t>(name, out_val, out);
+        if (!success)
+            OGS_FATAL(
+                "writePropertiesBinary: Could not write PropertyVector '%s'.",
+                name.c_str());
+    }
+    unsigned long offset = 0;
+    for (const auto& partition : _partitions)
+    {
+        MeshLib::IO::PropertyVectorPartitionMetaData pvpmd;
+        pvpmd.offset = offset;
+        pvpmd.number_of_tuples = partition.nodes.size();
+        INFO(
+            "Write meta data for PropertyVector: global offset %d, number "
+            "of tuples %d",
+            pvpmd.offset, pvpmd.number_of_tuples);
+        MeshLib::IO::writePropertyVectorPartitionMetaData(out, pvpmd);
+        offset += pvpmd.number_of_tuples;
+    }
+    out.close();
+    out_val.close();
+}
+
 std::tuple<std::vector<NodeWiseMeshPartitioner::IntegerType>,
            std::vector<NodeWiseMeshPartitioner::IntegerType>>
 NodeWiseMeshPartitioner::writeConfigDataBinary(
@@ -392,6 +510,7 @@ void NodeWiseMeshPartitioner::writeNodesBinary(const std::string& file_name_base
     const std::string fname = file_name_base + "_partitioned_msh_nod"
                               + std::to_string(_npartitions) + ".bin";
     FILE* of_bin_nod = fopen(fname.c_str(), "wb");
+
     for (const auto& partition : _partitions)
     {
         std::vector<NodeStruct> nodes_buffer;
@@ -415,6 +534,7 @@ void NodeWiseMeshPartitioner::writeNodesBinary(const std::string& file_name_base
 
 void NodeWiseMeshPartitioner::writeBinary(const std::string& file_name_base)
 {
+    writePropertiesBinary(file_name_base);
     const auto elem_integers = writeConfigDataBinary(file_name_base);
 
     const std::vector<IntegerType>& num_elem_integers
diff --git a/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.h b/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.h
index 40f3fc3b1adee9db02003e607d30a32a23bec3c8..db7fb985b15ea307c4ce53cce4c7c3d9dbcd2ded 100644
--- a/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.h
+++ b/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.h
@@ -21,6 +21,8 @@
 #include <fstream>
 
 #include "MeshLib/Mesh.h"
+#include "MeshLib/Node.h"
+#include "MeshLib/IO/MPI_IO/PropertyVectorMetaData.h"
 
 namespace ApplicationUtils
 {
@@ -51,10 +53,10 @@ public:
                             std::unique_ptr<MeshLib::Mesh>&& mesh)
         : _npartitions(num_partitions),
           _partitions(num_partitions),
+          _partitioned_properties(),
           _mesh(std::move(mesh)),
           _nodes_global_ids(_mesh->getNumberOfNodes()),
-          _nodes_partition_ids(_mesh->getNumberOfNodes()),
-          _elements_status(_mesh->getNumberOfElements(), false)
+          _nodes_partition_ids(_mesh->getNumberOfNodes())
     {
     }
 
@@ -87,6 +89,9 @@ private:
     /// Data for all  partitions.
     std::vector<Partition> _partitions;
 
+    /// Properties where values at ghost nodes and extra nodes are inserted.
+    MeshLib::Properties _partitioned_properties;
+
     /// Pointer to a mesh object.
     std::unique_ptr<MeshLib::Mesh> _mesh;
 
@@ -96,9 +101,6 @@ private:
     /// Partition IDs of each nodes.
     std::vector<std::size_t> _nodes_partition_ids;
 
-    /// Flags to indicate that whether elements are processed or not.
-    std::vector<bool> _elements_status;
-
     // Renumber the global indices of nodes,
     /// \param is_mixed_high_order_linear_elems Flag to indicate whether the
     /// elements of a mesh can be used for both linear and high order
@@ -128,6 +130,106 @@ private:
                                     std::vector<IntegerType>& elem_info,
                                     IntegerType& counter);
 
+    void writePropertiesBinary(std::string const& file_name_base) const;
+
+    /// 1 copy pointers to nodes belonging to the partition part_id
+    /// 2 collect non-linear element nodes belonging to the partition part_id in
+    /// extra_nodes
+    void findNonGhostNodesInPartition(
+        std::size_t const part_id,
+        const bool is_mixed_high_order_linear_elems,
+        std::vector<MeshLib::Node*>& extra_nodes);
+
+    /// 1 find elements belonging to the partition part_id:
+    /// fills vector partition.regular_elements
+    /// 2 find ghost elements belonging to the partition part_id
+    /// fills vector partition.ghost_elements
+    void findElementsInPartition(std::size_t const part_id,
+                                 const bool is_mixed_high_order_linear_elems);
+
+    /// Prerequisite: the ghost elements has to be found (using
+    /// findElementsInPartition).
+    /// Finds ghost nodes and non-linear element ghost nodes by walking over
+    /// ghost elements.
+    void findGhostNodesInPartition(std::size_t const part_id,
+                                   const bool is_mixed_high_order_linear_elems,
+                                   std::vector<MeshLib::Node*>& extra_nodes);
+
+    void splitOfHigherOrderNode(std::vector<MeshLib::Node*> const& nodes,
+                                bool const is_mixed_high_order_linear_elems,
+                                unsigned const node_id,
+                                std::vector<MeshLib::Node*>& base_nodes,
+                                std::vector<MeshLib::Node*>& extra_nodes);
+
+    void processPartition(std::size_t const part_id,
+                          const bool is_mixed_high_order_linear_elems);
+
+    void processProperties();
+
+    template <typename T>
+    bool copyPropertyVector(std::string const& name,
+                            std::size_t const total_number_of_tuples)
+    {
+        auto const& original_properties(_mesh->getProperties());
+        if (!original_properties.existsPropertyVector<T>(name))
+            return false;
+
+        auto const& pv(original_properties.getPropertyVector<T>(name));
+        auto partitioned_pv =
+            _partitioned_properties.createNewPropertyVector<T>(
+                name, pv->getMeshItemType(), pv->getNumberOfComponents());
+        partitioned_pv->resize(total_number_of_tuples *
+                               pv->getNumberOfComponents());
+        std::size_t position_offset(0);
+        for (auto p : _partitions)
+        {
+            for (std::size_t i = 0; i < p.nodes.size(); ++i)
+            {
+                const auto global_id = p.nodes[i]->getID();
+                (*partitioned_pv)[position_offset + i] = (*pv)[global_id];
+            }
+            position_offset += p.nodes.size();
+        }
+        return true;
+    }
+
+    template <typename T>
+    void writePropertyVectorValuesBinary(
+        std::ostream& os, MeshLib::PropertyVector<T> const& pv) const
+    {
+        std::size_t number_of_components(pv.getNumberOfComponents());
+        std::size_t number_of_tuples(pv.getNumberOfTuples());
+        std::vector<T> property_vector_buffer;
+        property_vector_buffer.resize(number_of_tuples * number_of_components);
+        for (std::size_t i = 0; i < pv.getNumberOfTuples(); ++i)
+        {
+            for (std::size_t c(0); c < number_of_components; ++c)
+                property_vector_buffer[i * number_of_components + c] =
+                    pv.getComponent(i, c);
+        }
+        os.write(reinterpret_cast<char*>(property_vector_buffer.data()),
+                 number_of_components * number_of_tuples * sizeof(T));
+    }
+
+    template <typename T>
+    bool writePropertyVectorBinary(std::string const& name,
+                                   std::ostream& out_val,
+                                   std::ostream& out_meta) const
+    {
+        if (!_partitioned_properties.existsPropertyVector<T>(name))
+            return false;
+
+        MeshLib::IO::PropertyVectorMetaData pvmd;
+        pvmd.property_name = name;
+        auto* pv = _partitioned_properties.getPropertyVector<T>(name);
+        pvmd.fillPropertyVectorMetaDataTypeInfo<T>();
+        pvmd.number_of_components = pv->getNumberOfComponents();
+        pvmd.number_of_tuples = pv->getNumberOfTuples();
+        writePropertyVectorValuesBinary(out_val, *pv);
+        MeshLib::IO::writePropertyVectorMetaDataBinary(out_meta, pvmd);
+        return true;
+     }
+
     /*!
          \brief Write the configuration data of the partition data in
                 binary files.
@@ -137,8 +239,8 @@ private:
                  element 2: The numbers of all ghost element integer
                             variables of each partitions.
     */
-    std::tuple< std::vector<IntegerType>, std::vector<IntegerType>>
-         writeConfigDataBinary(const std::string& file_name_base);
+    std::tuple<std::vector<IntegerType>, std::vector<IntegerType>>
+    writeConfigDataBinary(const std::string& file_name_base);
 
     /*!
          \brief Write the element integer variables of all partitions
diff --git a/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.cpp b/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.cpp
index 8e3d2f0f7a6611cbf28504525767d42231feaa16..c4f24d992af8ee220d7efa68a0ead8fb02db5eae 100644
--- a/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.cpp
+++ b/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.cpp
@@ -16,6 +16,10 @@
 
 #include <logog/include/logog.hpp>
 
+#ifdef USE_PETSC
+#include <mpi.h>
+#endif
+
 #include "BaseLib/FileTools.h"
 #include "BaseLib/RunTime.h"
 
@@ -184,8 +188,125 @@ MeshLib::NodePartitionedMesh* NodePartitionedMeshReader::readBinary(
     setElements(mesh_nodes, ghost_elem_data, mesh_elems, process_ghost);
 
     //----------------------------------------------------------------------------------
-    return newMesh(BaseLib::extractBaseName(file_name_base),
-               mesh_nodes, glb_node_ids, mesh_elems);
+    // read the properties
+    MeshLib::Properties p(readPropertiesBinary(file_name_base));
+
+    return newMesh(BaseLib::extractBaseName(file_name_base), mesh_nodes,
+                   glb_node_ids, mesh_elems, p);
+}
+
+MeshLib::Properties NodePartitionedMeshReader::readPropertiesBinary(
+    const std::string& file_name_base) const
+{
+    const std::string fname_cfg = file_name_base +
+                                  "_partitioned_properties_cfg" +
+                                  std::to_string(_mpi_comm_size) + ".bin";
+    std::ifstream is(fname_cfg.c_str(), std::ios::binary | std::ios::in);
+    if (!is)
+    {
+        WARN("Could not open file '%s' in binary mode.", fname_cfg.c_str());
+        return MeshLib::Properties();
+    }
+    std::size_t number_of_properties = 0;
+    is.read(reinterpret_cast<char*>(&number_of_properties), sizeof(std::size_t));
+    std::vector<boost::optional<MeshLib::IO::PropertyVectorMetaData>> vec_pvmd(
+        number_of_properties);
+    for (std::size_t i(0); i < number_of_properties; ++i)
+    {
+        vec_pvmd[i] = MeshLib::IO::readPropertyVectorMetaData(is);
+        if (!vec_pvmd[i])
+        {
+            OGS_FATAL(
+                "Error in NodePartitionedMeshReader::readPropertiesBinary: "
+                "Could not read the meta data for the PropertyVector %d",
+                i);
+        }
+    }
+    for (std::size_t i(0); i < number_of_properties; ++i)
+    {
+        DBUG("[%d] +++++++++++++", _mpi_rank);
+        MeshLib::IO::writePropertyVectorMetaData(*(vec_pvmd[i]));
+        DBUG("[%d] +++++++++++++", _mpi_rank);
+    }
+    auto pos = is.tellg();
+    auto offset =
+        pos +
+        static_cast<long>(_mpi_rank *
+                          sizeof(MeshLib::IO::PropertyVectorPartitionMetaData));
+    is.seekg(offset);
+    boost::optional<MeshLib::IO::PropertyVectorPartitionMetaData> pvpmd(
+        MeshLib::IO::readPropertyVectorPartitionMetaData(is));
+    bool pvpmd_read_ok = static_cast<bool>(pvpmd);
+    bool all_pvpmd_read_ok;
+    MPI_Allreduce(&pvpmd_read_ok, &all_pvpmd_read_ok, 1, MPI_C_BOOL, MPI_LOR,
+                  _mpi_comm);
+    if (!all_pvpmd_read_ok)
+    {
+        OGS_FATAL(
+            "Error in NodePartitionedMeshReader::readPropertiesBinary: "
+            "Could not read the partition meta data for the mpi process %d",
+            _mpi_rank);
+    }
+    DBUG("[%d] offset in the PropertyVector: %d", _mpi_rank, pvpmd->offset);
+    DBUG("[%d] %d tuples in partition.", _mpi_rank, pvpmd->number_of_tuples);
+    is.close();
+
+    const std::string fname_val = file_name_base + "_partitioned_properties_val"
+                              + std::to_string(_mpi_comm_size) + ".bin";
+    is.open(fname_val.c_str(), std::ios::binary | std::ios::in);
+    if (!is)
+    {
+        ERR("Could not open file '%s' in binary mode.", fname_val.c_str());
+    }
+
+    MeshLib::Properties p;
+
+    // Read the specific parts of the PropertyVector values for this process.
+    unsigned long global_offset = 0;
+    for (std::size_t i(0); i < number_of_properties; ++i)
+    {
+        INFO("[%d] global offset: %d, offset within the PropertyVector: %d.",
+             _mpi_rank, global_offset,
+             global_offset +
+                 pvpmd->offset * vec_pvmd[i]->data_type_size_in_bytes);
+        if (vec_pvmd[i]->is_int_type)
+        {
+            if (vec_pvmd[i]->is_data_type_signed)
+            {
+                if (vec_pvmd[i]->data_type_size_in_bytes == sizeof(int))
+                    createPropertyVectorPart<int>(is, *vec_pvmd[i], *pvpmd,
+                                                  global_offset, p);
+                if (vec_pvmd[i]->data_type_size_in_bytes == sizeof(long))
+                    createPropertyVectorPart<long>(is, *vec_pvmd[i], *pvpmd,
+                                                   global_offset, p);
+            }
+            else
+            {
+                if (vec_pvmd[i]->data_type_size_in_bytes ==
+                    sizeof(unsigned int))
+                    createPropertyVectorPart<unsigned int>(
+                        is, *vec_pvmd[i], *pvpmd, global_offset, p);
+                if (vec_pvmd[i]->data_type_size_in_bytes ==
+                    sizeof(unsigned long))
+                    createPropertyVectorPart<unsigned long>(
+                        is, *vec_pvmd[i], *pvpmd, global_offset, p);
+            }
+        }
+        else
+        {
+            if (vec_pvmd[i]->data_type_size_in_bytes == sizeof(float))
+                createPropertyVectorPart<float>(is, *vec_pvmd[i], *pvpmd,
+                                                global_offset, p);
+            if (vec_pvmd[i]->data_type_size_in_bytes == sizeof(double))
+                createPropertyVectorPart<double>(is, *vec_pvmd[i], *pvpmd,
+                                                 global_offset, p);
+        }
+        global_offset += vec_pvmd[i]->data_type_size_in_bytes *
+                         vec_pvmd[i]->number_of_tuples *
+                         vec_pvmd[i]->number_of_components;
+    }
+
+    return p;
 }
 
 bool NodePartitionedMeshReader::openASCIIFiles(std::string const& file_name_base,
@@ -369,28 +490,31 @@ MeshLib::NodePartitionedMesh* NodePartitionedMeshReader::readASCII(
         MPI_Bcast(_mesh_info.data(), static_cast<int>(_mesh_info.size()),
             MPI_LONG, 0, _mpi_comm);
 
-        //----------------------------------------------------------------------------------
+        //---------------------------------------------------------------------
         // Read Nodes
         if (!readCastNodesASCII(is_node, i, mesh_nodes, glb_node_ids))
             break;
 
-        //----------------------------------------------------------------------------------
+        //---------------------------------------------------------------------
         // Read elements
         if (!readCastElemsASCII(is_elem, i,
             _mesh_info.regular_elements + _mesh_info.offset[0],
             false, mesh_nodes, mesh_elems))
             break;
 
-        //-------------------------------------------------------------------------
+        //---------------------------------------------------------------------
         // Ghost elements
         if (!readCastElemsASCII(is_elem, i,
             _mesh_info.ghost_elements + _mesh_info.offset[1],
             true, mesh_nodes, mesh_elems))
             break;
 
-        if(_mpi_rank == i)
+        if(_mpi_rank == i) {
+            // reading ascii properties is not implemented
+            MeshLib::Properties properties;
             np_mesh = newMesh(BaseLib::extractBaseName(file_name_base),
-                    mesh_nodes, glb_node_ids, mesh_elems);
+                    mesh_nodes, glb_node_ids, mesh_elems, properties);
+        }
     }
 
     if(_mpi_rank == 0)
@@ -405,17 +529,17 @@ MeshLib::NodePartitionedMesh* NodePartitionedMeshReader::readASCII(
     return np_mesh;
 }
 
-MeshLib::NodePartitionedMesh*
-NodePartitionedMeshReader::newMesh(
+MeshLib::NodePartitionedMesh* NodePartitionedMeshReader::newMesh(
     std::string const& mesh_name,
     std::vector<MeshLib::Node*> const& mesh_nodes,
     std::vector<unsigned long> const& glb_node_ids,
-    std::vector<MeshLib::Element*> const& mesh_elems) const
+    std::vector<MeshLib::Element*> const& mesh_elems,
+    MeshLib::Properties const& properties) const
 {
     return new MeshLib::NodePartitionedMesh(
         mesh_name + std::to_string(_mpi_comm_size),
         mesh_nodes, glb_node_ids, mesh_elems,
-        MeshLib::Properties(),
+        properties,
         _mesh_info.global_base_nodes,
         _mesh_info.global_nodes,
         _mesh_info.base_nodes,
diff --git a/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.h b/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.h
index 26e4a9f2488938d08d69b2813271c446b294499b..6fbfc2d7832b5b7b87d3c3da8ff4813984a3b287 100644
--- a/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.h
+++ b/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.h
@@ -20,11 +20,14 @@
 #include <mpi.h>
 
 #include "MeshLib/NodePartitionedMesh.h"
+#include "MeshLib/Properties.h"
+#include "MeshLib/IO/MPI_IO/PropertyVectorMetaData.h"
 
 namespace MeshLib
 {
 class Node;
 class Element;
+class Properties;
 
 namespace IO
 {
@@ -100,17 +103,21 @@ private:
     } _mesh_info;
 
     /*!
-        \brief Create a new mesh of NodePartitionedMesh after reading and processing the data.
+        \brief Create a new mesh of NodePartitionedMesh after reading and
+       processing the data.
         \param mesh_name    Name assigned to the new mesh.
         \param mesh_nodes   Node data.
         \param glb_node_ids Global IDs of nodes.
         \param mesh_elems   Element data.
-        \return             True on success and false otherwise.
+        \param properties Collection of PropertyVector's assigned to the mesh.
+        \return Returns a pointer to a NodePartitionedMesh
      */
-    MeshLib::NodePartitionedMesh* newMesh(std::string const& mesh_name,
+    MeshLib::NodePartitionedMesh* newMesh(
+        std::string const& mesh_name,
         std::vector<MeshLib::Node*> const& mesh_nodes,
         std::vector<unsigned long> const& glb_node_ids,
-        std::vector<MeshLib::Element*> const& mesh_elems) const;
+        std::vector<MeshLib::Element*> const& mesh_elems,
+        MeshLib::Properties const& properties) const;
 
     /*!
         \brief Parallel reading of a binary file via MPI_File_read, and it is called by readBinary
@@ -158,18 +165,49 @@ private:
      */
     MeshLib::NodePartitionedMesh* readBinary(const std::string &file_name_base);
 
+    MeshLib::Properties readPropertiesBinary(const std::string& file_name_base) const;
+
+    template <typename T>
+    void createPropertyVectorPart(
+        std::istream& is, MeshLib::IO::PropertyVectorMetaData const& pvmd,
+        MeshLib::IO::PropertyVectorPartitionMetaData const& pvpmd,
+        unsigned long global_offset, MeshLib::Properties& p) const
+    {
+        MeshLib::PropertyVector<T>* pv =
+            p.createNewPropertyVector<T>(pvmd.property_name,
+                                         MeshLib::MeshItemType::Node,
+                                         pvmd.number_of_components);
+        pv->resize(pvpmd.number_of_tuples * pvmd.number_of_components);
+        // jump to the place for reading the specific part of the
+        // PropertyVector
+        is.seekg(global_offset + pvpmd.offset * sizeof(T));
+        // read the values
+        unsigned long const number_of_bytes = pvmd.data_type_size_in_bytes *
+                                              pvpmd.number_of_tuples *
+                                              pvmd.number_of_components;
+        if (!is.read(reinterpret_cast<char*>(pv->data()), number_of_bytes))
+            OGS_FATAL(
+                "Error in NodePartitionedMeshReader::readPropertiesBinary: "
+                "Could not read part %d of the PropertyVector.",
+                _mpi_rank);
+    }
+
     /*!
         \brief Open ASCII files of node partitioned mesh data.
 
-        \param file_name_base  Name of file to be read, which must be a name with the
+        \param file_name_base  Name of file to be read, which must be a name
+       with the
                                path to the file and without file extension.
-        \param is_cfg          Input stream for the file contains configuration data.
+        \param is_cfg          Input stream for the file contains
+       configuration data.
         \param is_node         Input stream for the file contains node data.
-        \param is_elem         Input stream for the file contains element data.
+        \param is_elem         Input stream for the file contains element
+       data.
         \return                Return true if all files are good.
      */
-    bool openASCIIFiles(std::string const& file_name_base,std::ifstream& is_cfg,
-        std::ifstream& is_node, std::ifstream& is_elem) const;
+    bool openASCIIFiles(std::string const& file_name_base,
+                        std::ifstream& is_cfg, std::ifstream& is_node,
+                        std::ifstream& is_elem) const;
 
     /*!
         \brief Read mesh nodes from an ASCII file and cast to the corresponding rank.
diff --git a/MeshLib/IO/MPI_IO/PropertyVectorMetaData.h b/MeshLib/IO/MPI_IO/PropertyVectorMetaData.h
new file mode 100644
index 0000000000000000000000000000000000000000..0d1e45fd6bd5123be04d88858aaf4695b3e6795b
--- /dev/null
+++ b/MeshLib/IO/MPI_IO/PropertyVectorMetaData.h
@@ -0,0 +1,144 @@
+/**
+ * \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 <string>
+#include <boost/optional.hpp>
+
+namespace MeshLib
+{
+namespace IO
+{
+
+struct PropertyVectorMetaData
+{
+    std::string property_name;
+    /// is_int_type is true if the type of the components is an integer type, if
+    /// it is a floating point number type the is_int_type is false
+    bool is_int_type;
+    /// if the component type is an integer number the flag is_data_type_signed
+    /// signals if it has a sign or not
+    bool is_data_type_signed;
+    unsigned long data_type_size_in_bytes;
+    unsigned long number_of_components;
+    unsigned long number_of_tuples;
+
+    template <typename T>
+    void fillPropertyVectorMetaDataTypeInfo()
+    {
+        is_int_type = std::numeric_limits<T>::is_integer;
+        is_data_type_signed = std::numeric_limits<T>::is_signed;
+        data_type_size_in_bytes = sizeof(T);
+    }
+};
+
+inline void writePropertyVectorMetaDataBinary(
+    std::ostream& os, PropertyVectorMetaData const& pvmd)
+{
+    std::string::size_type s(pvmd.property_name.length());
+    os.write(reinterpret_cast<char*>(&s), sizeof(std::string::size_type));
+
+    os.write(
+        const_cast<char*>(
+            const_cast<PropertyVectorMetaData&>(pvmd).property_name.data()),
+        s);
+    os.write(reinterpret_cast<char*>(
+                 &const_cast<PropertyVectorMetaData&>(pvmd).is_int_type),
+             sizeof(bool));
+    os.write(reinterpret_cast<char*>(&const_cast<PropertyVectorMetaData&>(
+                 pvmd).is_data_type_signed),
+             sizeof(bool));
+    os.write(reinterpret_cast<char*>(&const_cast<PropertyVectorMetaData&>(
+                 pvmd).data_type_size_in_bytes),
+             sizeof(unsigned long));
+    os.write(reinterpret_cast<char*>(&const_cast<PropertyVectorMetaData&>(
+                 pvmd).number_of_components),
+             sizeof(unsigned long));
+    os.write(reinterpret_cast<char*>(
+                 &const_cast<PropertyVectorMetaData&>(pvmd).number_of_tuples),
+             sizeof(unsigned long));
+}
+
+inline void writePropertyVectorMetaData(PropertyVectorMetaData const& pvmd)
+{
+    DBUG("size of name: %d", pvmd.property_name.length());
+    DBUG("name: '%s'", pvmd.property_name.c_str());
+    DBUG("is_int_data_type: %d", pvmd.is_int_type);
+    DBUG("is_data_type_signed: %d", pvmd.is_data_type_signed);
+    DBUG("data_type_size_in_bytes: %d", pvmd.data_type_size_in_bytes);
+    DBUG("number of components: i%d", pvmd.number_of_components);
+    DBUG("number of tuples: %d", pvmd.number_of_tuples);
+}
+
+inline boost::optional<PropertyVectorMetaData> readPropertyVectorMetaData(
+    std::istream& is)
+{
+    // read the size of the name of the PropertyVector
+    std::string::size_type s = 0;
+    if (!is.read(reinterpret_cast<char*>(&s), sizeof(std::string::size_type)))
+        return boost::optional<PropertyVectorMetaData>();
+
+    PropertyVectorMetaData pvmd;
+    char *dummy = new char[s];
+    if (!is.read(dummy, s))
+        return boost::none;
+    pvmd.property_name = std::string(dummy, s);
+    delete [] dummy;
+
+    if(!is.read(reinterpret_cast<char*>(&pvmd.is_int_type), sizeof(bool)))
+        return boost::none;
+    if(!is.read(reinterpret_cast<char*>(&pvmd.is_data_type_signed), sizeof(bool)))
+        return boost::none;
+    if(!is.read(reinterpret_cast<char*>(&pvmd.data_type_size_in_bytes),
+            sizeof(unsigned long)))
+        return boost::none;
+    if(!is.read(reinterpret_cast<char*>(&pvmd.number_of_components),
+            sizeof(unsigned long)))
+        return boost::none;
+    if(!is.read(reinterpret_cast<char*>(&pvmd.number_of_tuples),
+            sizeof(unsigned long)))
+        return boost::none;
+    return boost::optional<PropertyVectorMetaData>(pvmd);
+}
+
+struct PropertyVectorPartitionMetaData
+{
+    unsigned long offset;
+    unsigned long number_of_tuples;
+};
+
+inline void writePropertyVectorPartitionMetaData(
+    std::ostream& os, PropertyVectorPartitionMetaData const& pvpmd)
+{
+    os.write(reinterpret_cast<char*>(
+                 &const_cast<PropertyVectorPartitionMetaData&>(pvpmd)
+                      .offset),
+             sizeof(unsigned long));
+    os.write(reinterpret_cast<char*>(
+                 &const_cast<PropertyVectorPartitionMetaData&>(pvpmd)
+                      .number_of_tuples),
+             sizeof(unsigned long));
+}
+
+inline boost::optional<PropertyVectorPartitionMetaData>
+readPropertyVectorPartitionMetaData(std::istream& is)
+{
+    PropertyVectorPartitionMetaData pvpmd;
+    if (!is.read(reinterpret_cast<char*>(&pvpmd.offset),
+                 sizeof(unsigned long)))
+        return boost::optional<PropertyVectorPartitionMetaData>();
+    if (!is.read(reinterpret_cast<char*>(&pvpmd.number_of_tuples),
+                 sizeof(unsigned long)))
+        return boost::optional<PropertyVectorPartitionMetaData>();
+    return boost::optional<PropertyVectorPartitionMetaData>(pvpmd);
+}
+}
+}