diff --git a/Applications/DataExplorer/DataView/DirectConditionGenerator.cpp b/Applications/DataExplorer/DataView/DirectConditionGenerator.cpp
index c6e5f3f80325f30ee066961d02d03701fd6c84b3..04fde58032915728d201a5365c7e103b67ca826d 100644
--- a/Applications/DataExplorer/DataView/DirectConditionGenerator.cpp
+++ b/Applications/DataExplorer/DataView/DirectConditionGenerator.cpp
@@ -97,22 +97,23 @@ const std::vector< std::pair<std::size_t,double> >& DirectConditionGenerator::di
     const std::size_t nNodes(surface_mesh->getNumberOfNodes());
     const double no_data(raster->getHeader().no_data);
 
-    auto const* const node_id_pv =
-        surface_mesh->getProperties().getPropertyVector<int>(prop_name);
-    if (!node_id_pv)
+    MeshLib::PropertyVector<int> const* node_id_pv = nullptr;
+    try
     {
-        ERR(
-            "Need subsurface node ids, but the property \"%s\" is not "
-            "available.",
-            prop_name.c_str());
+        node_id_pv = surface_mesh->getProperties().getPropertyVector<int>(
+            prop_name, MeshLib::MeshItemType::Node, 1);
+    }
+    catch (std::runtime_error const& e)
+    {
+        WARN("%s", e.what());
         return _direct_values;
     }
 
     _direct_values.reserve(nNodes);
-    for (std::size_t i=0; i<nNodes; ++i)
+    for (std::size_t i = 0; i < nNodes; ++i)
     {
         double val(raster->getValueAtPoint(*surface_nodes[i]));
-        val = (val == no_data) ? 0 : ((val*node_area_vec[i])/scaling);
+        val = (val == no_data) ? 0 : ((val * node_area_vec[i]) / scaling);
         _direct_values.emplace_back((*node_id_pv)[i], val);
     }
 
diff --git a/Applications/DataExplorer/DataView/ElementTreeModel.cpp b/Applications/DataExplorer/DataView/ElementTreeModel.cpp
index 9f3efbd8272fbd49fe463f0017a18cabf3e6af64..bc407df5d31e2afafc6ac316a8c2ab918cf5c01b 100644
--- a/Applications/DataExplorer/DataView/ElementTreeModel.cpp
+++ b/Applications/DataExplorer/DataView/ElementTreeModel.cpp
@@ -65,9 +65,11 @@ void ElementTreeModel::setElement(vtkUnstructuredGridAlgorithm const*const grid,
     auto* typeItem = new TreeItem(typeData, elemItem);
     elemItem->appendChild(typeItem);
 
-    MeshLib::PropertyVector<int> const*const mat_ids =
-        mesh->getProperties().existsPropertyVector<int>("MaterialIDs")
-            ? mesh->getProperties().getPropertyVector<int>("MaterialIDs")
+    MeshLib::PropertyVector<int> const* const mat_ids =
+        mesh->getProperties().existsPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1)
+            ? mesh->getProperties().getPropertyVector<int>(
+                  "MaterialIDs", MeshLib::MeshItemType::Cell, 1)
             : nullptr;
     QString matIdString = !mat_ids ? QString("not defined") : QString::number((*mat_ids)[elem->getID()]);
     QList<QVariant> materialData;
diff --git a/Applications/Utils/FileConverter/generateMatPropsFromMatID.cpp b/Applications/Utils/FileConverter/generateMatPropsFromMatID.cpp
index b8c312d408de0639b5d3a2f79f3f78f9e484981e..31b7c3162bd58a8abb3f41d37b11b221cbde032a 100644
--- a/Applications/Utils/FileConverter/generateMatPropsFromMatID.cpp
+++ b/Applications/Utils/FileConverter/generateMatPropsFromMatID.cpp
@@ -52,31 +52,38 @@ int main (int argc, char* argv[])
     cmd.parse( argc, argv );
 
     // read mesh
-    std::unique_ptr<MeshLib::Mesh> mesh(MeshLib::IO::readMeshFromFile(mesh_arg.getValue()));
-    if (!mesh) {
+    std::unique_ptr<MeshLib::Mesh> mesh(
+        MeshLib::IO::readMeshFromFile(mesh_arg.getValue()));
+
+    if (!mesh)
+    {
         INFO("Could not read mesh from file \"%s\".", mesh_arg.getValue().c_str());
         return EXIT_FAILURE;
     }
-    if (!mesh->getProperties().existsPropertyVector<int>("MaterialIDs"))
+
+    MeshLib::PropertyVector<int>* materialIds = nullptr;
+    try
+    {
+        materialIds = mesh->getProperties().getPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
+    }
+    catch (std::runtime_error const& e)
     {
-        ERR("Mesh contains no int-property vector named \"MaterialIds\".");
+        WARN("%s", e.what());
         return EXIT_FAILURE;
     }
-    auto materialIds = mesh->getProperties().getPropertyVector<int>("MaterialIDs");
 
     std::size_t const n_properties(materialIds->size());
-    if (n_properties != mesh->getNumberOfElements()) {
-        ERR("Size mismatch: number of elements (%u) != number of material "
-            "properties (%u).", mesh->getNumberOfElements(), n_properties);
-        return EXIT_FAILURE;
-    }
-    std::string const name = BaseLib::extractBaseNameWithoutExtension(mesh_arg.getValue());
+    assert(n_properties != mesh->getNumberOfElements());
+
+    std::string const name =
+        BaseLib::extractBaseNameWithoutExtension(mesh_arg.getValue());
     // create file
     std::string const new_matname(name + "_prop");
-    std::ofstream out_prop( new_matname.c_str(), std::ios::out );
+    std::ofstream out_prop(new_matname.c_str(), std::ios::out);
     if (out_prop.is_open())
     {
-        for (std::size_t i=0; i<n_properties; ++i)
+        for (std::size_t i = 0; i < n_properties; ++i)
             out_prop << i << "\t" << (*materialIds)[i] << "\n";
         out_prop.close();
     }
@@ -92,7 +99,8 @@ int main (int argc, char* argv[])
     INFO("Writing mesh to file \"%s\".", new_mshname.c_str());
     MeshLib::IO::writeMeshToFile(*mesh, new_mshname);
 
-    INFO("New files \"%s\" and \"%s\" written.", new_mshname.c_str(), new_matname.c_str());
+    INFO("New files \"%s\" and \"%s\" written.", new_mshname.c_str(),
+         new_matname.c_str());
 
     return EXIT_SUCCESS;
 }
diff --git a/Applications/Utils/MeshEdit/queryMesh.cpp b/Applications/Utils/MeshEdit/queryMesh.cpp
index f40fcf3ca501bfd8838688b59baf925806ecb71f..44bd0156e2a282ca49a1ccf351fb0eca109f93f3 100644
--- a/Applications/Utils/MeshEdit/queryMesh.cpp
+++ b/Applications/Utils/MeshEdit/queryMesh.cpp
@@ -68,9 +68,11 @@ int main(int argc, char *argv[])
     }
     selected_node_ids.insert(selected_node_ids.end(), nodeId_arg.getValue().begin(), nodeId_arg.getValue().end());
 
-    MeshLib::PropertyVector<int> const*const materialIds =
-        mesh->getProperties().existsPropertyVector<int>("MaterialIDs")
-            ? mesh->getProperties().getPropertyVector<int>("MaterialIDs")
+    MeshLib::PropertyVector<int> const* const materialIds =
+        mesh->getProperties().existsPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1)
+            ? mesh->getProperties().getPropertyVector<int>(
+                  "MaterialIDs", MeshLib::MeshItemType::Cell, 1)
             : nullptr;
     for (auto ele_id : eleId_arg.getValue())
     {
diff --git a/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp b/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp
index e6db7224059a4ee5c3039b68e7c908d8076823fa..b46a67a8b1b6dd14d69f709cec1ea86477f389a0 100644
--- a/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp
+++ b/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp
@@ -600,7 +600,8 @@ std::vector<Partition> NodeWiseMeshPartitioner::partitionOtherMesh(
     bool const is_mixed_high_order_linear_elems) const
 {
     auto const& bulk_node_ids =
-        mesh.getProperties().getPropertyVector<std::size_t>("bulk_node_ids");
+        mesh.getProperties().getPropertyVector<std::size_t>(
+            "bulk_node_ids", MeshLib::MeshItemType::Node, 1);
 
     std::vector<Partition> partitions(_partitions.size());
     for (std::size_t part_id = 0; part_id < _partitions.size(); part_id++)
diff --git a/Applications/Utils/ModelPreparation/PartitionMesh/PartitionMesh.cpp b/Applications/Utils/ModelPreparation/PartitionMesh/PartitionMesh.cpp
index a8f66b7974284dfa81c2075f8333e9518813cafa..59c2e845a7ebe8f19ca2bb62ea3da14c29b3a8e6 100644
--- a/Applications/Utils/ModelPreparation/PartitionMesh/PartitionMesh.cpp
+++ b/Applications/Utils/ModelPreparation/PartitionMesh/PartitionMesh.cpp
@@ -187,11 +187,11 @@ int main(int argc, char* argv[])
             partitionProperties(mesh->getProperties(), partitions);
         mesh_partitioner.renumberBulkNodeIdsProperty(
             partitioned_properties.getPropertyVector<std::size_t>(
-                "bulk_node_ids"),
+                "bulk_node_ids", MeshLib::MeshItemType::Node, 1),
             partitions);
         mesh_partitioner.renumberBulkElementIdsProperty(
             partitioned_properties.getPropertyVector<std::size_t>(
-                "bulk_element_ids"),
+                "bulk_element_ids", MeshLib::MeshItemType::Cell, 1),
             partitions);
         mesh_partitioner.writeOtherMesh(output_file_name_wo_extension,
                                         partitions, partitioned_properties);
diff --git a/Applications/Utils/ModelPreparation/createNeumannBc.cpp b/Applications/Utils/ModelPreparation/createNeumannBc.cpp
index 1a1f50781712d141a31bc19192ae92cd993afba4..80c131ff60f153b62eb18a3ee6073d07fc373beb 100644
--- a/Applications/Utils/ModelPreparation/createNeumannBc.cpp
+++ b/Applications/Utils/ModelPreparation/createNeumannBc.cpp
@@ -45,8 +45,8 @@ std::vector<double> getSurfaceIntegratedValuesForNodes(
             prop_name.c_str());
         return std::vector<double>();
     }
-    auto const* const elem_pv =
-        mesh.getProperties().getPropertyVector<double>(prop_name);
+    auto const* const elem_pv = mesh.getProperties().getPropertyVector<double>(
+        prop_name, MeshLib::MeshItemType::Cell, 1);
 
     std::vector<double> integrated_node_area_vec;
     double total_area(0);
@@ -133,17 +133,21 @@ int main(int argc, char* argv[])
     std::unique_ptr<MeshLib::Mesh> surface_mesh(
         MeshLib::IO::readMeshFromFile(in_mesh.getValue()));
 
-    std::string const prop_name("bulk_node_ids");
     auto const* const node_id_pv =
-        surface_mesh->getProperties().getPropertyVector<std::size_t>(prop_name);
+        [&]() -> MeshLib::PropertyVector<std::size_t>* {
+        try
+        {
+            return surface_mesh->getProperties().getPropertyVector<std::size_t>(
+                "bulk_node_ids", MeshLib::MeshItemType::Node, 1);
+        }
+        catch (std::runtime_error const& e)
+        {
+            WARN("%s", e.what());
+            return nullptr;
+        }
+    }();
     if (!node_id_pv)
-    {
-        ERR(
-            "Need subsurface node ids, but the property \"%s\" is not "
-            "available.",
-            prop_name.c_str());
         return EXIT_FAILURE;
-    }
 
     std::vector<double> integrated_values = getSurfaceIntegratedValuesForNodes(
         *surface_mesh, property_in_arg.getValue());
@@ -162,13 +166,14 @@ int main(int argc, char* argv[])
         surface_mesh->getProperties().createNewPropertyVector<double>(
             property_out_arg.getValue(), MeshLib::MeshItemType::Node, 1);
     pv->resize(surface_mesh->getNodes().size());
-    for (std::size_t k(0); k<surface_mesh->getNodes().size(); ++k) {
+    for (std::size_t k(0); k < surface_mesh->getNodes().size(); ++k)
+    {
         (*pv)[k] = direct_values[k].second;
     }
 
     MeshLib::IO::writeMeshToFile(*surface_mesh, result_file.getValue());
 
-    std::ofstream result_out(result_file.getValue()+".txt");
+    std::ofstream result_out(result_file.getValue() + ".txt");
     result_out.precision(std::numeric_limits<double>::digits10);
     for (auto const& p : direct_values)
         result_out << p.first << " " << p.second << "\n";
diff --git a/MaterialLib/PorousMedium/CreatePorousMediaProperties.cpp b/MaterialLib/PorousMedium/CreatePorousMediaProperties.cpp
index 79ba16737f1ef638eecbeb721309dd6aa6cb8245..45ac97c4f86566aed8564ea31b7b6d61dfef172c 100644
--- a/MaterialLib/PorousMedium/CreatePorousMediaProperties.cpp
+++ b/MaterialLib/PorousMedium/CreatePorousMediaProperties.cpp
@@ -77,10 +77,12 @@ PorousMediaProperties createPorousMediaProperties(
     BaseLib::reorderVector(storage_models, mat_ids);
 
     std::vector<int> material_ids(mesh.getNumberOfElements());
-    if (mesh.getProperties().existsPropertyVector<int>("MaterialIDs"))
+    if (mesh.getProperties().existsPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1))
     {
         auto const& mesh_material_ids =
-            mesh.getProperties().getPropertyVector<int>("MaterialIDs");
+            mesh.getProperties().getPropertyVector<int>(
+                "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
         material_ids.reserve(mesh_material_ids->size());
         std::copy(mesh_material_ids->cbegin(), mesh_material_ids->cend(),
                   material_ids.begin());
diff --git a/MeshGeoToolsLib/AppendLinesAlongPolyline.cpp b/MeshGeoToolsLib/AppendLinesAlongPolyline.cpp
index 4e06ff99459db8d3f3b84cdfe519b0e9be843f70..c107c4d10896e4f90037229c9677bd25b273cd1b 100644
--- a/MeshGeoToolsLib/AppendLinesAlongPolyline.cpp
+++ b/MeshGeoToolsLib/AppendLinesAlongPolyline.cpp
@@ -33,14 +33,16 @@ std::unique_ptr<MeshLib::Mesh> appendLinesAlongPolylines(
     std::vector<MeshLib::Element*> vec_new_eles = MeshLib::copyElementVector(mesh.getElements(), vec_new_nodes);
 
     std::vector<int> new_mat_ids;
+    try
     {
-        if (mesh.getProperties().existsPropertyVector<int>("MaterialIDs")) {
-            auto ids =
-                mesh.getProperties().getPropertyVector<int>("MaterialIDs");
-            new_mat_ids.reserve(ids->size());
-            std::copy(ids->cbegin(), ids->cend(),
-                      std::back_inserter(new_mat_ids));
-        }
+        auto ids = mesh.getProperties().getPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
+        new_mat_ids.reserve(ids->size());
+        std::copy(ids->cbegin(), ids->cend(), std::back_inserter(new_mat_ids));
+    }
+    catch (std::runtime_error const& e)
+    {
+        WARN("%s", e.what());
     }
     int max_matID(0);
     if (!new_mat_ids.empty())
diff --git a/MeshGeoToolsLib/IdentifySubdomainMesh.cpp b/MeshGeoToolsLib/IdentifySubdomainMesh.cpp
index 5b69d073d90ad38f28af3c494ff5ccdda75bb40b..07c0313b0a7bec1eb8207b0bfe3130e55f27a13b 100644
--- a/MeshGeoToolsLib/IdentifySubdomainMesh.cpp
+++ b/MeshGeoToolsLib/IdentifySubdomainMesh.cpp
@@ -99,8 +99,8 @@ std::vector<std::vector<std::size_t>> identifySubdomainMeshElements(
     MeshLib::Mesh const& subdomain_mesh, MeshLib::Mesh const& bulk_mesh)
 {
     auto& properties = subdomain_mesh.getProperties();
-    auto const& bulk_node_ids =
-        *properties.getPropertyVector<std::size_t>("bulk_node_ids");
+    auto const& bulk_node_ids = *properties.getPropertyVector<std::size_t>(
+        "bulk_node_ids", MeshLib::MeshItemType::Node, 1);
 
     // Allocate space for all elements for random insertion.
     std::vector<std::vector<std::size_t>> bulk_element_ids_map(
diff --git a/MeshLib/Mesh.cpp b/MeshLib/Mesh.cpp
index 57a148fa85e95bdfcbfb55a52500742e36ee210b..df7855873676dd3bb958bf6f7a60a23e423aa180 100644
--- a/MeshLib/Mesh.cpp
+++ b/MeshLib/Mesh.cpp
@@ -342,8 +342,10 @@ void scaleMeshPropertyVector(MeshLib::Mesh & mesh,
 PropertyVector<int> const* materialIDs(Mesh const& mesh)
 {
     auto const& properties = mesh.getProperties();
-    return properties.existsPropertyVector<int>("MaterialIDs")
-               ? properties.getPropertyVector<int>("MaterialIDs")
+    return properties.existsPropertyVector<int>("MaterialIDs",
+                                                MeshLib::MeshItemType::Cell, 1)
+               ? properties.getPropertyVector<int>(
+                     "MaterialIDs", MeshLib::MeshItemType::Cell, 1)
                : nullptr;
 }
 
diff --git a/MeshLib/MeshEditing/ElementValueModification.cpp b/MeshLib/MeshEditing/ElementValueModification.cpp
index aae1e4ddf381db41a8a7069f3b9dd5313123864e..096ddd63fc74756fea6aeed3b66dd3fb76a1b04b 100644
--- a/MeshLib/MeshEditing/ElementValueModification.cpp
+++ b/MeshLib/MeshEditing/ElementValueModification.cpp
@@ -28,12 +28,17 @@ bool ElementValueModification::replace(MeshLib::Mesh &mesh,
     std::string const& property_name, int const old_value, int const new_value,
     bool replace_if_exists)
 {
-    if (!mesh.getProperties().existsPropertyVector<int>(property_name))
+    MeshLib::PropertyVector<int>* property_value_vec = nullptr;
+    try
     {
+        property_value_vec = mesh.getProperties().getPropertyVector<int>(
+            property_name, MeshLib::MeshItemType::Cell, 1);
+    }
+    catch (std::runtime_error const& e)
+    {
+        ERR("%s", e.what());
         return false;
     }
-    auto* const property_value_vec =
-        mesh.getProperties().getPropertyVector<int>(property_name);
 
     const std::size_t n_property_tuples(
         property_value_vec->getNumberOfTuples());
@@ -71,20 +76,24 @@ bool ElementValueModification::replace(MeshLib::Mesh &mesh,
 
 std::size_t ElementValueModification::condense(MeshLib::Mesh &mesh)
 {
-    auto* property_value_vector =
-        mesh.getProperties().getPropertyVector<int>("MaterialIDs");
-
-    if (!property_value_vector)
+    MeshLib::PropertyVector<int>* property_value_vector = nullptr;
+    try
+    {
+        property_value_vector = mesh.getProperties().getPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
+    }
+    catch (std::runtime_error const& e)
     {
+        ERR("%s", e.what());
         return 0;
     }
 
     std::vector<int> value_mapping(
         getSortedPropertyValues(*property_value_vector));
 
-    std::vector<int> reverse_mapping(value_mapping.back()+1, 0);
-    std::size_t const nValues (value_mapping.size());
-    for (std::size_t i=0; i<nValues; ++i)
+    std::vector<int> reverse_mapping(value_mapping.back() + 1, 0);
+    std::size_t const nValues(value_mapping.size());
+    for (std::size_t i = 0; i < nValues; ++i)
         reverse_mapping[value_mapping[i]] = i;
 
     std::size_t const n_property_values(property_value_vector->size());
@@ -97,18 +106,23 @@ std::size_t ElementValueModification::condense(MeshLib::Mesh &mesh)
 
 std::size_t ElementValueModification::setByElementType(MeshLib::Mesh &mesh, MeshElemType ele_type, int const new_value)
 {
-    auto* const property_value_vector =
-        mesh.getProperties().getPropertyVector<int>("MaterialIDs");
-
-    if (!property_value_vector)
+    MeshLib::PropertyVector<int>* property_value_vector = nullptr;
+    try
+    {
+        property_value_vector = mesh.getProperties().getPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
+    }
+    catch (std::runtime_error const& e)
     {
+        ERR("%s", e.what());
         return 0;
     }
 
     std::vector<MeshLib::Element*> const& elements(mesh.getElements());
     std::size_t cnt(0);
-    for (std::size_t k(0); k<elements.size(); k++) {
-        if (elements[k]->getGeomType()!=ele_type)
+    for (std::size_t k(0); k < elements.size(); k++)
+    {
+        if (elements[k]->getGeomType() != ele_type)
             continue;
         (*property_value_vector)[k] = new_value;
         cnt++;
diff --git a/MeshLib/MeshSearch/ElementSearch.h b/MeshLib/MeshSearch/ElementSearch.h
index d8631bf879e3fec3429ab60eca5250473fcb8db8..cd163726ee29afed0c9b7001d29d1e53aafa3e1f 100644
--- a/MeshLib/MeshSearch/ElementSearch.h
+++ b/MeshLib/MeshSearch/ElementSearch.h
@@ -72,24 +72,18 @@ public:
         PROPERTY_TYPE const max_property_value,
         bool outside_of)
     {
-        if (!_mesh.getProperties().existsPropertyVector<PROPERTY_TYPE>(property_name))
+        MeshLib::PropertyVector<PROPERTY_TYPE> const* pv = nullptr;
+        try
         {
-            WARN("Property \"%s\" not found in mesh.", property_name.c_str());
-            return 0;
-        }
-        auto const* const pv =
-            _mesh.getProperties().getPropertyVector<PROPERTY_TYPE>(property_name);
-
-        if (pv->getMeshItemType() != MeshLib::MeshItemType::Cell)
-        {
-            WARN("The property \"%s\" is not assigned to mesh elements.",
-                 property_name.c_str());
-            return 0;
+            pv = _mesh.getProperties().getPropertyVector<PROPERTY_TYPE>(
+                property_name, MeshLib::MeshItemType::Cell, 1);
         }
-
-        if (pv->getNumberOfComponents() != 1)
+        catch (std::runtime_error const& e)
         {
-            WARN("Value-based element removal currently only works for scalars.");
+            ERR("%s", e.what());
+            WARN(
+                "Value-based element removal currently only works for "
+                "scalars.");
             return 0;
         }
 
@@ -99,7 +93,8 @@ public:
         {
             for (std::size_t i(0); i < pv->getNumberOfTuples(); ++i)
             {
-                if ((*pv)[i] < min_property_value || (*pv)[i] > max_property_value)
+                if ((*pv)[i] < min_property_value ||
+                    (*pv)[i] > max_property_value)
                     matchedIDs.push_back(i);
             }
         }
@@ -107,7 +102,8 @@ public:
         {
             for (std::size_t i(0); i < pv->getNumberOfTuples(); ++i)
             {
-                if ((*pv)[i] >= min_property_value && (*pv)[i] <= max_property_value)
+                if ((*pv)[i] >= min_property_value &&
+                    (*pv)[i] <= max_property_value)
                     matchedIDs.push_back(i);
             }
         }
diff --git a/MeshLib/Properties-impl.h b/MeshLib/Properties-impl.h
index 960da18e007bbee9cd9682e8a08671ee2c60e07f..6b105c70367521cc83c3a3d7b36af5fab0d3e9f6 100644
--- a/MeshLib/Properties-impl.h
+++ b/MeshLib/Properties-impl.h
@@ -87,6 +87,33 @@ bool Properties::existsPropertyVector(std::string const& name) const
     return dynamic_cast<PropertyVector<T> const*>(it->second) != nullptr;
 }
 
+template <typename T>
+bool Properties::existsPropertyVector(std::string const& name,
+                                      MeshItemType const mesh_item_type,
+                                      int const number_of_components) const
+{
+    auto const it = _properties.find(name);
+    if (it == _properties.end())
+    {
+        return false;
+    }
+
+    auto property = dynamic_cast<PropertyVector<T>*>(it->second);
+    if (property == nullptr)
+    {
+        return false;
+    }
+    if (property->getMeshItemType() != mesh_item_type)
+    {
+        return false;
+    }
+    if (property->getNumberOfComponents() != number_of_components)
+    {
+        return false;
+    }
+    return true;
+}
+
 template <typename T>
 PropertyVector<T> const* Properties::getPropertyVector(
     std::string const& name) const
@@ -136,25 +163,66 @@ PropertyVector<T> const* Properties::getPropertyVector(
     auto const it = _properties.find(name);
     if (it == _properties.end())
     {
-        OGS_FATAL("A property with name '%s' does not exist.", name.c_str());
+        OGS_FATAL("A PropertyVector with name '%s' does not exist in the mesh.",
+                  name.c_str());
     }
 
     auto property = dynamic_cast<PropertyVector<T>*>(it->second);
     if (property == nullptr)
     {
-        OGS_FATAL("Could not cast property '%s' to given type.", name.c_str());
+        OGS_FATAL(
+            "Could not cast the data type of the PropertyVector '%s' to "
+            "requested data type.",
+            name.c_str());
     }
     if (property->getMeshItemType() != item_type)
     {
         OGS_FATAL(
-            "The PropertyVector '%s' has a different type than requested. A "
-            "'%s' field is requested.",
-            name.c_str(), toString(item_type));
+            "The PropertyVector '%s' has type '%s'. A '%s' field is requested.",
+            name.c_str(), toString(property->getMeshItemType()),
+            toString(item_type));
     }
     if (property->getNumberOfComponents() != n_components)
     {
-        OGS_FATAL("'%s' does not have the right number of components.",
+        OGS_FATAL(
+            "PropertyVector '%s' has %d components, %d components are needed.",
+            name.c_str(), property->getNumberOfComponents(), n_components);
+    }
+    return property;
+}
+
+template <typename T>
+PropertyVector<T>* Properties::getPropertyVector(std::string const& name,
+                                                 MeshItemType const item_type,
+                                                 int const n_components)
+{
+    auto const it = _properties.find(name);
+    if (it == _properties.end())
+    {
+        OGS_FATAL("A PropertyVector with name '%s' does not exist in the mesh.",
                   name.c_str());
     }
+
+    auto property = dynamic_cast<PropertyVector<T>*>(it->second);
+    if (property == nullptr)
+    {
+        OGS_FATAL(
+            "Could not cast the data type of the PropertyVector '%s' to "
+            "requested data type.",
+            name.c_str());
+    }
+    if (property->getMeshItemType() != item_type)
+    {
+        OGS_FATAL(
+            "The PropertyVector '%s' has type '%s'. A '%s' field is requested.",
+            name.c_str(), toString(property->getMeshItemType()),
+            toString(item_type));
+    }
+    if (property->getNumberOfComponents() != n_components)
+    {
+        OGS_FATAL(
+            "PropertyVector '%s' has %d components, %d components are needed.",
+            name.c_str(), property->getNumberOfComponents(), n_components);
+    }
     return property;
 }
diff --git a/MeshLib/Properties.h b/MeshLib/Properties.h
index 220889273ce304535c789317a54ffc5c6ab45ab5..638a4b2b4b63b2c3ecde7943411dd8183c368937 100644
--- a/MeshLib/Properties.h
+++ b/MeshLib/Properties.h
@@ -85,6 +85,13 @@ public:
     template <typename T>
     bool existsPropertyVector(std::string const& name) const;
 
+    /// Checks if a property vector with given type \c T, \c name, \c
+    /// mesh_item_type, and \c number_of_components exists.
+    template <typename T>
+    bool existsPropertyVector(std::string const& property_name,
+                              MeshItemType const mesh_item_type,
+                              int const number_of_components) const;
+
     /// Returns a property vector with given \c name or aborts calling OGS_FATAL
     /// if no such property vector exists.
     template <typename T>
@@ -103,6 +110,14 @@ public:
                                                MeshItemType const item_type,
                                                int const n_components) const;
 
+    /// Non-const version of getPropertyVector returns a property vector with
+    /// given \c name, \c item_type and \c number_of_components or calls
+    /// OGS_FATAL if no such property vector exists.
+    template <typename T>
+    PropertyVector<T>* getPropertyVector(std::string const& name,
+                                         MeshItemType const item_type,
+                                         int const number_of_components);
+
     void removePropertyVector(std::string const& name);
 
     /// Check if a PropertyVector accessible by the name is already
diff --git a/NumLib/DOF/MeshComponentMap.cpp b/NumLib/DOF/MeshComponentMap.cpp
index 97bb45d67b22ed6cd8495a07c54598417f2d8c4e..969870e0fc7a0485e1a9d5ac4e7afe883d4e7caa 100644
--- a/NumLib/DOF/MeshComponentMap.cpp
+++ b/NumLib/DOF/MeshComponentMap.cpp
@@ -148,7 +148,7 @@ MeshComponentMap MeshComponentMap::getSubset(
     }
     auto const& bulk_node_ids_map =
         *new_mesh_properties.template getPropertyVector<std::size_t>(
-            "bulk_node_ids");
+            "bulk_node_ids", MeshLib::MeshItemType::Node, 1);
 
     // New dictionary for the subset.
     ComponentGlobalIndexDict subset_dict;
diff --git a/ProcessLib/BoundaryCondition/ConstraintDirichletBoundaryCondition.cpp b/ProcessLib/BoundaryCondition/ConstraintDirichletBoundaryCondition.cpp
index 21c3d379715133401441cba1c517c54b1c9c1f96..f4e6b041dcc7f2802d80ec4d034c41d495c9ad7e 100644
--- a/ProcessLib/BoundaryCondition/ConstraintDirichletBoundaryCondition.cpp
+++ b/ProcessLib/BoundaryCondition/ConstraintDirichletBoundaryCondition.cpp
@@ -70,24 +70,10 @@ ConstraintDirichletBoundaryCondition::ConstraintDirichletBoundaryCondition(
     // create _bulk_ids vector
     auto const* bulk_element_ids =
         _bc_mesh.getProperties().getPropertyVector<std::size_t>(
-            "bulk_element_ids");
-    if (!bulk_element_ids)
-    {
-        OGS_FATAL(
-            "The boundary mesh '%s' doesn't contain the needed property "
-            "'bulk_element_ids'.",
-            _bc_mesh.getName().c_str());
-    }
+            "bulk_element_ids", MeshLib::MeshItemType::Cell, 1);
     auto const* bulk_node_ids =
         _bc_mesh.getProperties().getPropertyVector<std::size_t>(
-            "bulk_node_ids");
-    if (!bulk_node_ids)
-    {
-        OGS_FATAL(
-            "The boundary mesh '%s' doesn't contain the needed property "
-            "'bulk_node_ids'.",
-            _bc_mesh.getName().c_str());
-    }
+            "bulk_node_ids", MeshLib::MeshItemType::Node, 1);
     auto const& bulk_nodes = bulk_mesh.getNodes();
 
     auto get_bulk_element_face_id =
diff --git a/ProcessLib/BoundaryCondition/NonuniformDirichletBoundaryCondition.cpp b/ProcessLib/BoundaryCondition/NonuniformDirichletBoundaryCondition.cpp
index 4efba29d19468fa157d638c8741f3df1f9d93b3e..8f3d189aa4382943d302797caccb7fe49de33829 100644
--- a/ProcessLib/BoundaryCondition/NonuniformDirichletBoundaryCondition.cpp
+++ b/ProcessLib/BoundaryCondition/NonuniformDirichletBoundaryCondition.cpp
@@ -32,7 +32,8 @@ createNonuniformDirichletBoundaryCondition(
         config.getConfigParameter<std::string>("field_name");
 
     auto const* const property =
-        boundary_mesh.getProperties().getPropertyVector<double>(field_name);
+        boundary_mesh.getProperties().getPropertyVector<double>(
+            field_name, MeshLib::MeshItemType::Node, 1);
 
     if (!property)
     {
@@ -40,19 +41,6 @@ createNonuniformDirichletBoundaryCondition(
                   field_name.c_str(), boundary_mesh.getName().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());
-    }
-
     // In case of partitioned mesh the boundary could be empty, i.e. there is no
     // boundary condition.
 #ifdef USE_PETSC
diff --git a/ProcessLib/BoundaryCondition/Python/PythonBoundaryCondition.cpp b/ProcessLib/BoundaryCondition/Python/PythonBoundaryCondition.cpp
index 3df5a5473aebaf702bc91f4a713cdc4aa9d1effa..20aec500456566f559f4bf58b023e2577131e2ec 100644
--- a/ProcessLib/BoundaryCondition/Python/PythonBoundaryCondition.cpp
+++ b/ProcessLib/BoundaryCondition/Python/PythonBoundaryCondition.cpp
@@ -87,7 +87,7 @@ void PythonBoundaryCondition::getEssentialBCValues(
 
     auto const& bulk_node_ids_map =
         *_bc_data.boundary_mesh.getProperties().getPropertyVector<std::size_t>(
-            "bulk_node_ids");
+            "bulk_node_ids", MeshLib::MeshItemType::Node, 1);
 
     bc_values.ids.clear();
     bc_values.values.clear();
diff --git a/ProcessLib/BoundaryCondition/Python/PythonBoundaryConditionLocalAssembler.h b/ProcessLib/BoundaryCondition/Python/PythonBoundaryConditionLocalAssembler.h
index 6018fa210f48770982ff8a1352ab26fdf7279d35..83fbc8f10fa3f3e6e98688b7483370b150a72af3 100644
--- a/ProcessLib/BoundaryCondition/Python/PythonBoundaryConditionLocalAssembler.h
+++ b/ProcessLib/BoundaryCondition/Python/PythonBoundaryConditionLocalAssembler.h
@@ -68,7 +68,8 @@ public:
 
         auto const& bulk_node_ids_map =
             *_data.boundary_mesh.getProperties()
-                 .template getPropertyVector<std::size_t>("bulk_node_ids");
+                 .template getPropertyVector<std::size_t>(
+                     "bulk_node_ids", MeshLib::MeshItemType::Node, 1);
 
         // gather primary variables
         Eigen::MatrixXd primary_variables_mat(num_nodes, num_comp_total);
diff --git a/ProcessLib/LIE/Common/MeshUtils.cpp b/ProcessLib/LIE/Common/MeshUtils.cpp
index 9fa1349ee32cc77ac2cbfb0e862745379b3be56a..0e13861aaeab0eabc9d8f0e65e76bc4b2347033e 100644
--- a/ProcessLib/LIE/Common/MeshUtils.cpp
+++ b/ProcessLib/LIE/Common/MeshUtils.cpp
@@ -84,8 +84,8 @@ void getFractureMatrixDataInMesh(
          vec_matrix_elements.size(), all_fracture_elements.size());
 
     // get fracture material IDs
-    auto opt_material_ids(
-        mesh.getProperties().getPropertyVector<int>("MaterialIDs"));
+    auto opt_material_ids(mesh.getProperties().getPropertyVector<int>(
+        "MaterialIDs", MeshLib::MeshItemType::Cell, 1));
     for (MeshLib::Element* e : all_fracture_elements)
         vec_fracture_mat_IDs.push_back((*opt_material_ids)[e->getID()]);
     BaseLib::makeVectorUnique(vec_fracture_mat_IDs);
diff --git a/ProcessLib/LIE/HydroMechanics/HydroMechanicsProcess.cpp b/ProcessLib/LIE/HydroMechanics/HydroMechanicsProcess.cpp
index d1c64ca41efcb13dac072150771bb90fb0dd9ffe..48f9b926593c22f8f67dbf17ec7cccdb8f51ab7f 100644
--- a/ProcessLib/LIE/HydroMechanics/HydroMechanicsProcess.cpp
+++ b/ProcessLib/LIE/HydroMechanics/HydroMechanicsProcess.cpp
@@ -318,8 +318,8 @@ void HydroMechanicsProcess<GlobalDim>::initializeConcreteProcess(
             const_cast<MeshLib::Mesh&>(mesh), "aperture",
             MeshLib::MeshItemType::Cell, 1);
         mesh_prop_b->resize(mesh.getNumberOfElements());
-        auto mesh_prop_matid =
-            mesh.getProperties().getPropertyVector<int>("MaterialIDs");
+        auto mesh_prop_matid = mesh.getProperties().getPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
         auto frac = _process_data.fracture_property.get();
         for (MeshLib::Element const* e : _mesh.getElements())
         {
diff --git a/ProcessLib/LiquidFlow/CreateLiquidFlowProcess.cpp b/ProcessLib/LiquidFlow/CreateLiquidFlowProcess.cpp
index 51a53a7ddb19c5d3602ff2e9b6d6a393a2a168a1..f8fc4511dc3923cc35a2f3b2e4b2e6f42516462c 100644
--- a/ProcessLib/LiquidFlow/CreateLiquidFlowProcess.cpp
+++ b/ProcessLib/LiquidFlow/CreateLiquidFlowProcess.cpp
@@ -91,12 +91,13 @@ std::unique_ptr<Process> createLiquidFlowProcess(
     //! \ogs_file_param{prj__processes__process__LIQUID_FLOW__material_property}
     auto const& mat_config = config.getConfigSubtree("material_property");
 
-    if (mesh.getProperties().existsPropertyVector<int>("MaterialIDs"))
+    if (mesh.getProperties().existsPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1))
     {
         INFO("The liquid flow is in heterogeneous porous media.");
         const bool has_material_ids = true;
-        auto const& mat_ids =
-            mesh.getProperties().getPropertyVector<int>("MaterialIDs");
+        auto const& mat_ids = mesh.getProperties().getPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
         return std::unique_ptr<Process>{new LiquidFlowProcess{
             mesh, std::move(jacobian_assembler), parameters, integration_order,
             std::move(process_variables), std::move(secondary_variables),
diff --git a/ProcessLib/RichardsFlow/CreateRichardsFlowProcess.cpp b/ProcessLib/RichardsFlow/CreateRichardsFlowProcess.cpp
index f0651c3825b8d45236815889cd977936a64e0279..ab9694e8661834adef9fe385a57a5e7b055c3729 100644
--- a/ProcessLib/RichardsFlow/CreateRichardsFlowProcess.cpp
+++ b/ProcessLib/RichardsFlow/CreateRichardsFlowProcess.cpp
@@ -80,8 +80,12 @@ std::unique_ptr<Process> createRichardsFlowProcess(
     //! \ogs_file_param{prj__processes__process__RICHARDS_FLOW__material_property}
     auto const& mat_config = config.getConfigSubtree("material_property");
 
-    auto const material_ids =
-        mesh.getProperties().getPropertyVector<int>("MaterialIDs");
+    auto const* material_ids =
+        mesh.getProperties().existsPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1)
+            ? mesh.getProperties().getPropertyVector<int>(
+                  "MaterialIDs", MeshLib::MeshItemType::Cell, 1)
+            : nullptr;
     if (material_ids != nullptr)
     {
         INFO("The Richards flow is in heterogeneous porous media.");
diff --git a/ProcessLib/SurfaceFlux/SurfaceFlux.cpp b/ProcessLib/SurfaceFlux/SurfaceFlux.cpp
index 35996b53126a74264fce81ae559412354c8314f3..a5735a825e81993585e2010a24ba7f13add4cf4b 100644
--- a/ProcessLib/SurfaceFlux/SurfaceFlux.cpp
+++ b/ProcessLib/SurfaceFlux/SurfaceFlux.cpp
@@ -40,10 +40,10 @@ SurfaceFlux::SurfaceFlux(
 
     auto const bulk_element_ids =
         boundary_mesh.getProperties().template getPropertyVector<std::size_t>(
-            "bulk_element_ids");
+            "bulk_element_ids", MeshLib::MeshItemType::Cell, 1);
     auto const bulk_face_ids =
         boundary_mesh.getProperties().template getPropertyVector<std::size_t>(
-            "bulk_face_ids");
+            "bulk_face_ids", MeshLib::MeshItemType::Cell, 1);
 
     ProcessLib::createLocalAssemblers<SurfaceFluxLocalAssembler>(
         boundary_mesh.getDimension() + 1,  // or bulk_mesh.getDimension()?
diff --git a/ProcessLib/TwoPhaseFlowWithPP/CreateTwoPhaseFlowWithPPProcess.cpp b/ProcessLib/TwoPhaseFlowWithPP/CreateTwoPhaseFlowWithPPProcess.cpp
index b210b4c7352516de93c4cf76940c7d98933710ea..e46d4d4d76e63058a9b0ec78e9285be558a3a5a5 100644
--- a/ProcessLib/TwoPhaseFlowWithPP/CreateTwoPhaseFlowWithPPProcess.cpp
+++ b/ProcessLib/TwoPhaseFlowWithPP/CreateTwoPhaseFlowWithPPProcess.cpp
@@ -79,11 +79,12 @@ std::unique_ptr<Process> createTwoPhaseFlowWithPPProcess(
     auto const& mat_config = config.getConfigSubtree("material_property");
 
     boost::optional<MeshLib::PropertyVector<int> const&> material_ids;
-    if (mesh.getProperties().existsPropertyVector<int>("MaterialIDs"))
+    if (mesh.getProperties().existsPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1))
     {
         INFO("The twophase flow is in heterogeneous porous media.");
-        material_ids =
-            *mesh.getProperties().getPropertyVector<int>("MaterialIDs");
+        material_ids = *mesh.getProperties().getPropertyVector<int>(
+            "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
     }
     else
     {