Repository: PowerGridModel/power-grid-model (language: cpp)

Issue:
[Release] v1.9.0
Decision during standup: minor version bump due to potential pylint/mypy stuff for our users from #648 

**Before release**

* [x] Update [`VERSION`](#VERSION) file if applicable
* [x] Make PR
* [x] Merge PR

**After release**

* [x] Update the release notes
  * [x] Add `Highlights` section if needed
  * [x] Any breaking changes: explain + provide migration approach
  * [x] Any deprecations: explain + provide migration approach
* [ ] Share with stakeholders
  * [x] Notify maintainers
  * [x] Post to PGM LF Energy mailing list
  * [x] Post to PGM LF Energy Slack channel
  * [x] Post to LinkedIn
  * [ ] Share in sprint review



Discussion / hints:

Fix patch:
diff --git a/VERSION b/VERSION
index 625934097..2e0e38c63 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-1.8
+1.9
diff --git a/code_generation/code_gen.py b/code_generation/code_gen.py
index 73e6d3423..32ec49a3d 100644
--- a/code_generation/code_gen.py
+++ b/code_generation/code_gen.py
@@ -114,7 +114,6 @@ def render_dataset_class_maps(self, template_path: Path, data_path: Path, output
                     for component_name in component.names:
                         all_components[component_name] = [x.names for x in class_def.full_attributes]
                 all_map[f"{prefix}{dataset.name}"] = all_components
-
         self.render_template(template_path=template_path, output_path=output_path, all_map=all_map)
 
     def code_gen(self):
diff --git a/code_generation/templates/src/power_grid_model/core/dataset_class_maps.py.jinja b/code_generation/templates/src/power_grid_model/core/dataset_class_maps.py.jinja
new file mode 100644
index 000000000..4fa699669
--- /dev/null
+++ b/code_generation/templates/src/power_grid_model/core/dataset_class_maps.py.jinja
@@ -0,0 +1,89 @@
+# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
+#
+# SPDX-License-Identifier: MPL-2.0
+
+"""Data types for power grid model dataset and component types."""
+
+# This file is automatically generated. DO NOT modify it manually!
+
+{%- set dataset_types = all_map.keys() %}
+{%- set components = all_map['input'].keys() %}
+
+from enum import Enum, EnumMeta
+from typing import Any, Dict, Mapping
+
+# pylint: disable=invalid-name
+
+# fmt: off
+
+class _MetaEnum(EnumMeta):
+    def __contains__(cls, member):
+        """
+        Check if member is part of the Enum.
+
+        Args:
+            member: Member to check.
+
+        Returns:
+            bool: True if the member is part of the Enum, False otherwise.
+        """
+        return member in cls.__members__.keys()
+
+
+class DatasetType(str, Enum, metaclass=_MetaEnum):
+    """
+    A DatasetType is the type of a :class:`Dataset` in power grid model.
+
+    - Examples:
+
+        - DatasetType.input = "input"
+        - DatasetType.update = "update"
+    """
+{% for dataset_type in dataset_types %}
+    {{ dataset_type }} = "{{ dataset_type }}"
+{%- endfor %}
+
+
+class ComponentType(str, Enum):
+    """
+    A ComponentType is the type of a grid component.
+
+    - Examples:
+
+        - ComponentType.node = "node"
+        - ComponentType.line = "line"
+    """
+{% for component in components %}
+    {{ component }} = "{{ component }}"
+{%- endfor %}
+
+
+# pylint: enable=invalid-name
+
+
+def _str_to_datatype(data_type: Any) -> DatasetType:
+    """Helper function to transform data_type str to DatasetType."""
+    if isinstance(data_type, str):
+        return DatasetType[data_type]
+    return data_type
+
+
+def _map_to_datatypes(data: Mapping[Any, Any]) -> Dict[DatasetType, Any]:
+    """Helper function to map datatype str keys to DatasetType."""
+    return {_str_to_datatype(key): value for key, value in data.items()}
+
+
+def _str_to_component_type(component: Any) -> ComponentType:
+    """Helper function to transform component str to ComponentType."""
+    if isinstance(component, str):
+        return ComponentType[component]
+    return component
+
+
+def _map_to_component_types(data: Mapping[Any, Any]) -> Dict[ComponentType, Any]:
+    """Helper function to map componenttype str keys to ComponentType."""
+    return {_str_to_component_type(key): value for key, value in data.items()}
+
+
+# fmt: on
+
diff --git a/docs/advanced_documentation/native-data-interface.md b/docs/advanced_documentation/native-data-interface.md
index eed5e7de4..0b17b8056 100644
--- a/docs/advanced_documentation/native-data-interface.md
+++ b/docs/advanced_documentation/native-data-interface.md
@@ -98,10 +98,12 @@ For example, the following update dataset will set `from_status` of the line #5
 and keep the `to_status` as unchanged (change not available).
 
 ```python
-from power_grid_model import power_grid_meta_data
+from power_grid_model import ComponentType, DatasetType, power_grid_meta_data
 import numpy as np
 
-line_update = np.empty(shape=1, dtype=power_grid_meta_data['update']['line']['dtype'])
+line_update = np.empty(shape=1, dtype=power_grid_meta_data[DatasetType.update][ComponentType.line]['dtype'])
+# direct string access is supported as well:
+# line_update = np.empty(shape=1, dtype=power_grid_meta_data['update']['line']['dtype'])
 line_update['id'] = [5]
 line_update['from_status'] = [0]
 line_update['to_status'] = [-128]
@@ -137,9 +139,11 @@ One can import the `power_grid_meta_data` to get all the predefined `numpy.dtype
 The code below creates an array which is compatible with transformer input dataset.
 
 ```python
-from power_grid_model import power_grid_meta_data
+from power_grid_model import ComponentType, DatasetType, power_grid_meta_data
 
-transformer = np.empty(shape=5, dtype=power_grid_meta_data['input']['transformer']['dtype'])
+transformer = np.empty(shape=5, dtype=power_grid_meta_data[DatasetType.input][ComponentType.transformer]['dtype'])
+# direct string access is supported as well:
+# transformer = np.empty(shape=5, dtype=power_grid_meta_data['input']['transformer']['dtype'])
 ```
 
 Furthermore, there is an even more convenient function `initialize_array`
diff --git a/docs/api_reference/python-api-reference.md b/docs/api_reference/python-api-reference.md
index 292213b8f..2e7b9c6ef 100644
--- a/docs/api_reference/python-api-reference.md
+++ b/docs/api_reference/python-api-reference.md
@@ -32,6 +32,8 @@ SPDX-License-Identifier: MPL-2.0
 .. autoclass:: power_grid_model.data_types.BatchArray
 .. autoclass:: power_grid_model.data_types.DenseBatchArray
 .. autoclass:: power_grid_model.data_types.SparseBatchArray
+.. autoclass:: power_grid_model.dataset_definitions.DatasetType
+.. autoclass:: power_grid_model.dataset_definitions.ComponentType
 ```
 
 ## error types
diff --git a/docs/examples/Asymmetric Calculation Example.ipynb b/docs/examples/Asymmetric Calculation Example.ipynb
index 032451a72..f349706fb 100644
--- a/docs/examples/Asymmetric Calculation Example.ipynb
+++ b/docs/examples/Asymmetric Calculation Example.ipynb
@@ -52,7 +52,7 @@
     "    # suppress warning about pyarrow as future required dependency\n",
     "    import pandas as pd\n",
     "\n",
-    "from power_grid_model import LoadGenType\n",
+    "from power_grid_model import LoadGenType, ComponentType, DatasetType\n",
     "from power_grid_model import PowerGridModel, CalculationMethod, CalculationType, MeasuredTerminalType\n",
     "from power_grid_model import initialize_array"
    ]
@@ -83,12 +83,12 @@
    "outputs": [],
    "source": [
     "# node\n",
-    "node = initialize_array(\"input\", \"node\", 3)\n",
+    "node = initialize_array(DatasetType.input, ComponentType.node, 3)\n",
     "node[\"id\"] = np.array([1, 2, 6])\n",
     "node[\"u_rated\"] = [10.5e3, 10.5e3, 10.5e3]\n",
     "\n",
     "# line\n",
-    "line = initialize_array(\"input\", \"line\", 3)\n",
+    "line = initialize_array(DatasetType.input, ComponentType.line, 3)\n",
     "line[\"id\"] = [3, 5, 8]\n",
     "line[\"from_node\"] = [1, 2, 1]\n",
     "line[\"to_node\"] = [2, 6, 6]\n",
@@ -105,7 +105,7 @@
     "line[\"tan0\"] = [0, 0, 0]\n",
     "\n",
     "# sym load\n",
-    "sym_load = initialize_array(\"input\", \"sym_load\", 1)\n",
+    "sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 1)\n",
     "sym_load[\"id\"] = [4]\n",
     "sym_load[\"node\"] = [2]\n",
     "sym_load[\"status\"] = [1]\n",
@@ -114,7 +114,7 @@
     "sym_load[\"q_specified\"] = [5e6]\n",
     "\n",
     "# asym load\n",
-    "asym_load = initialize_array(\"input\", \"asym_load\", 1)\n",
+    "asym_load = initialize_array(DatasetType.input, ComponentType.asym_load, 1)\n",
     "asym_load[\"id\"] = [7]\n",
     "asym_load[\"node\"] = [6]\n",
     "asym_load[\"status\"] = [1]\n",
@@ -123,7 +123,7 @@
     "asym_load[\"q_specified\"] = [[0, 8e6, 2e6]] # the 3 phases may have different loads\n",
     "\n",
     "# source\n",
-    "source = initialize_array(\"input\", \"source\", 1)\n",
+    "source = initialize_array(DatasetType.input, ComponentType.source, 1)\n",
     "source[\"id\"] = [10]\n",
     "source[\"node\"] = [1]\n",
     "source[\"status\"] = [1]\n",
@@ -131,11 +131,11 @@
     "\n",
     "# all\n",
     "asym_input_data = {\n",
-    "    \"node\": node,\n",
-    "    \"line\": line,\n",
-    "    \"sym_load\": sym_load,\n",
-    "    \"asym_load\": asym_load,\n",
-    "    \"source\": source\n",
+    "    ComponentType.node: node,\n",
+    "    ComponentType.line: line,\n",
+    "    ComponentType.sym_load: sym_load,\n",
+    "    ComponentType.asym_load: asym_load,\n",
+    "    ComponentType.source: source\n",
     "}"
    ]
   },
@@ -209,9 +209,9 @@
    ],
    "source": [
     "print(\"------node voltage result------\")\n",
-    "print(pd.DataFrame(asym_result[\"node\"][\"u\"]))\n",
+    "print(pd.DataFrame(asym_result[ComponentType.node][\"u\"]))\n",
     "print(\"------node angle result------\")\n",
-    "print(pd.DataFrame(asym_result[\"node\"][\"u_angle\"]))"
+    "print(pd.DataFrame(asym_result[ComponentType.node][\"u_angle\"]))"
    ]
   },
   {
@@ -269,7 +269,7 @@
    "outputs": [],
    "source": [
     "# note the shape of the array, 10 scenarios, 1 objects (asymmetric load_7)\n",
-    "load_profile = initialize_array(\"update\", \"asym_load\", (10, 1))  \n",
+    "load_profile = initialize_array(DatasetType.update, ComponentType.asym_load, (10, 1))  \n",
     "\n",
     "# this is a scale of asym_load from 0% to 100%------------------\n",
     "# the array is an (10, 1, 3) shape, which shows (scenario, object, phase).\n",
@@ -277,7 +277,7 @@
     "load_profile[\"id\"] = [7]\n",
     "load_profile[\"p_specified\"] = [10e6, 20e6 , 0] * np.linspace(0, 1, 10).reshape(-1, 1, 1)\n",
     "\n",
-    "time_series_mutation = {\"asym_load\": load_profile}"
+    "time_series_mutation = {ComponentType.asym_load: load_profile}"
    ]
   },
   {
@@ -389,7 +389,7 @@
     }
    ],
    "source": [
-    "display(pd.DataFrame(output_data[\"line\"][\"p_from\"][0]))"
+    "display(pd.DataFrame(output_data[ComponentType.line][\"p_from\"][0]))"
    ]
   },
   {
@@ -519,7 +519,7 @@
     }
    ],
    "source": [
-    "display(pd.DataFrame(output_data[\"line\"][\"i_from\"][:,0]))"
+    "display(pd.DataFrame(output_data[ComponentType.line][\"i_from\"][:,0]))"
    ]
   },
   {
@@ -541,14 +541,14 @@
    "outputs": [],
    "source": [
     "# sym voltage sensor\n",
-    "sym_voltage_sensor = initialize_array(\"input\", \"sym_voltage_sensor\", 2)\n",
+    "sym_voltage_sensor = initialize_array(DatasetType.input, ComponentType.sym_voltage_sensor, 2)\n",
     "sym_voltage_sensor[\"id\"] = [11, 12]\n",
     "sym_voltage_sensor[\"measured_object\"] = [1, 2]\n",
     "sym_voltage_sensor[\"u_sigma\"] = [100, 10]\n",
     "sym_voltage_sensor[\"u_measured\"] = [6000, 5500]\n",
     "\n",
     "# asym voltage sensor\n",
-    "asym_voltage_sensor = initialize_array(\"input\", \"asym_voltage_sensor\", 1)\n",
+    "asym_voltage_sensor = initialize_array(DatasetType.input, ComponentType.asym_voltage_sensor, 1)\n",
     "asym_voltage_sensor[\"id\"] = [13]\n",
     "asym_voltage_sensor[\"measured_object\"] = [6]\n",
     "asym_voltage_sensor[\"u_sigma\"] = [100]\n",
@@ -556,7 +556,7 @@
     "\n",
     "\n",
     "# sym power sensor\n",
-    "sym_power_sensor = initialize_array(\"input\", \"sym_power_sensor\", 7)\n",
+    "sym_power_sensor = initialize_array(DatasetType.input, ComponentType.sym_power_sensor, 7)\n",
     "sym_power_sensor[\"id\"] = [14, 15, 16, 17, 18, 19, 20]\n",
     "sym_power_sensor[\"measured_object\"] = [3, 3, 5, 5, 8, 8, 4]\n",
     "sym_power_sensor[\"measured_terminal_type\"] = [\n",
@@ -570,7 +570,7 @@
     "sym_power_sensor[\"q_measured\"] = [5e6, -7e6, 2e6, -2e6, 5e6, -5e6, 5e6]\n",
     "\n",
     "# asym power sensor\n",
-    "asym_power_sensor = initialize_array(\"input\", \"asym_power_sensor\", 1)\n",
+    "asym_power_sensor = initialize_array(DatasetType.input, ComponentType.asym_power_sensor, 1)\n",
     "asym_power_sensor[\"id\"] = [21]\n",
     "asym_power_sensor[\"measured_object\"] = [6]\n",
     "asym_power_sensor[\"measured_terminal_type\"] = [MeasuredTerminalType.node]\n",
@@ -580,15 +580,15 @@
     "\n",
     "# all \n",
     "asym_input_data = {\n",
-    "    \"node\": node,\n",
-    "    \"line\": line,\n",
-    "    \"sym_load\": sym_load,\n",
-    "    \"asym_load\": asym_load,\n",
-    "    \"source\": source,\n",
-    "    \"sym_voltage_sensor\": sym_voltage_sensor,\n",
-    "    \"asym_voltage_sensor\": asym_voltage_sensor,\n",
-    "    \"sym_power_sensor\": sym_power_sensor,\n",
-    "    \"asym_power_sensor\": asym_power_sensor,\n",
+    "    ComponentType.node: node,\n",
+    "    ComponentType.line: line,\n",
+    "    ComponentType.sym_load: sym_load,\n",
+    "    ComponentType.asym_load: asym_load,\n",
+    "    ComponentType.source: source,\n",
+    "    ComponentType.sym_voltage_sensor: sym_voltage_sensor,\n",
+    "    ComponentType.asym_voltage_sensor: asym_voltage_sensor,\n",
+    "    ComponentType.sym_power_sensor: sym_power_sensor,\n",
+    "    ComponentType.asym_power_sensor: asym_power_sensor,\n",
     "}"
    ]
   },
@@ -788,10 +788,10 @@
    ],
    "source": [
     "print(\"------node voltage result------\")\n",
-    "display(pd.DataFrame(asym_result[\"sym_voltage_sensor\"][\"u_residual\"]))\n",
+    "display(pd.DataFrame(asym_result[ComponentType.sym_voltage_sensor][\"u_residual\"]))\n",
     "\n",
     "print(\"------sym_load result------\")\n",
-    "display(pd.DataFrame(asym_result[\"sym_power_sensor\"][\"p_residual\"]))"
+    "display(pd.DataFrame(asym_result[ComponentType.sym_power_sensor][\"p_residual\"]))"
    ]
   },
   {
diff --git a/docs/examples/Make Test Dataset.ipynb b/docs/examples/Make Test Dataset.ipynb
index 3b47b1356..01bc6b60a 100644
--- a/docs/examples/Make Test Dataset.ipynb
+++ b/docs/examples/Make Test Dataset.ipynb
@@ -167,19 +167,19 @@
     "    # suppress warning about pyarrow as future required dependency\n",
     "    import pandas as pd\n",
     "\n",
-    "from power_grid_model import LoadGenType\n",
+    "from power_grid_model import LoadGenType, ComponentType, DatasetType\n",
     "from power_grid_model import PowerGridModel\n",
     "from power_grid_model import initialize_array\n",
     "\n",
     "# network\n",
     "\n",
     "# node\n",
-    "node = initialize_array(\"input\", \"node\", 3)\n",
+    "node = initialize_array(DatasetType.input, ComponentType.node, 3)\n",
     "node[\"id\"] = [1, 2, 6]\n",
     "node[\"u_rated\"] = [10.5e3, 10.5e3, 10.5e3]\n",
     "\n",
     "# line\n",
-    "line = initialize_array(\"input\", \"line\", 3)\n",
+    "line = initialize_array(DatasetType.input, ComponentType.line, 3)\n",
     "line[\"id\"] = [3, 5, 8]\n",
     "line[\"from_node\"] = [1, 2, 1]\n",
     "line[\"to_node\"] = [2, 6, 6]\n",
@@ -192,7 +192,7 @@
     "line[\"i_n\"] = [1000, 1000, 1000]\n",
     "\n",
     "# load\n",
-    "sym_load = initialize_array(\"input\", \"sym_load\", 2)\n",
+    "sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 2)\n",
     "sym_load[\"id\"] = [4, 7]\n",
     "sym_load[\"node\"] = [2, 6]\n",
     "sym_load[\"status\"] = [1, 1]\n",
@@ -201,14 +201,14 @@
     "sym_load[\"q_specified\"] = [5e6, 2e6]\n",
     "\n",
     "# source\n",
-    "source = initialize_array(\"input\", \"source\", 1)\n",
+    "source = initialize_array(DatasetType.input, ComponentType.source, 1)\n",
     "source[\"id\"] = [10]\n",
     "source[\"node\"] = [1]\n",
     "source[\"status\"] = [1]\n",
     "source[\"u_ref\"] = [1.0]\n",
     "\n",
     "# all\n",
-    "input_data = {\"node\": node, \"line\": line, \"sym_load\": sym_load, \"source\": source}"
+    "input_data = {ComponentType.node: node, ComponentType.line: line, ComponentType.sym_load: sym_load, ComponentType.source: source}"
    ]
   },
   {
@@ -318,7 +318,7 @@
     "pgm = PowerGridModel(imported_data)\n",
     "result = pgm.calculate_power_flow()\n",
     "\n",
-    "print(pd.DataFrame(result[\"node\"]))"
+    "print(pd.DataFrame(result[ComponentType.node]))"
    ]
   },
   {
@@ -340,13 +340,13 @@
    "source": [
     "# create batch set\n",
     "\n",
-    "load_profile = initialize_array(\"update\", \"sym_load\", (3, 2))\n",
+    "load_profile = initialize_array(DatasetType.update, ComponentType.sym_load, (3, 2))\n",
     "load_profile[\"id\"] = [[4, 7]]\n",
     "# this is a scale of load from 0% to 100%\n",
     "load_profile[\"p_specified\"] = [[30e6, 15e6]] * np.linspace(0, 1, 3).reshape(-1, 1)\n",
     "\n",
     "\n",
-    "time_series_mutation = {\"sym_load\": load_profile}"
+    "time_series_mutation = {ComponentType.sym_load: load_profile}"
    ]
   },
   {
@@ -420,7 +420,7 @@
     "\n",
     "batch_result = pgm.calculate_power_flow(update_data=imported_batch_update)\n",
     "\n",
-    "print(batch_result[\"sym_load\"][\"p\"])"
+    "print(batch_result[ComponentType.sym_load][\"p\"])"
    ]
   }
  ],
diff --git a/docs/examples/Power Flow Example.ipynb b/docs/examples/Power Flow Example.ipynb
index 8d130e456..aa37f1cb3 100644
--- a/docs/examples/Power Flow Example.ipynb
+++ b/docs/examples/Power Flow Example.ipynb
@@ -51,7 +51,7 @@
     "    # suppress warning about pyarrow as future required dependency\n",
     "    import pandas as pd\n",
     "\n",
-    "from power_grid_model import LoadGenType\n",
+    "from power_grid_model import LoadGenType, ComponentType, DatasetType\n",
     "from power_grid_model import PowerGridModel, CalculationMethod, CalculationType\n",
     "from power_grid_model import initialize_array"
    ]
@@ -80,12 +80,12 @@
    "outputs": [],
    "source": [
     "# node\n",
-    "node = initialize_array(\"input\", \"node\", 3)\n",
+    "node = initialize_array(DatasetType.input, ComponentType.node, 3)\n",
     "node[\"id\"] = np.array([1, 2, 6])\n",
     "node[\"u_rated\"] = [10.5e3, 10.5e3, 10.5e3]\n",
     "\n",
     "# line\n",
-    "line = initialize_array(\"input\", \"line\", 3)\n",
+    "line = initialize_array(DatasetType.input, ComponentType.line, 3)\n",
     "line[\"id\"] = [3, 5, 8]\n",
     "line[\"from_node\"] = [1, 2, 1]\n",
     "line[\"to_node\"] = [2, 6, 6]\n",
@@ -98,7 +98,7 @@
     "line[\"i_n\"] = [1000, 1000, 1000]\n",
     "\n",
     "# load\n",
-    "sym_load = initialize_array(\"input\", \"sym_load\", 2)\n",
+    "sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 2)\n",
     "sym_load[\"id\"] = [4, 7]\n",
     "sym_load[\"node\"] = [2, 6]\n",
     "sym_load[\"status\"] = [1, 1]\n",
@@ -107,7 +107,7 @@
     "sym_load[\"q_specified\"] = [5e6, 2e6]\n",
     "\n",
     "# source\n",
-    "source = initialize_array(\"input\", \"source\", 1)\n",
+    "source = initialize_array(DatasetType.input, ComponentType.source, 1)\n",
     "source[\"id\"] = [10]\n",
     "source[\"node\"] = [1]\n",
     "source[\"status\"] = [1]\n",
@@ -115,10 +115,10 @@
     "\n",
     "# all\n",
     "input_data = {\n",
-    "    \"node\": node,\n",
-    "    \"line\": line,\n",
-    "    \"sym_load\": sym_load,\n",
-    "    \"source\": source\n",
+    "    ComponentType.node: node,\n",
+    "    ComponentType.line: line,\n",
+    "    ComponentType.sym_load: sym_load,\n",
+    "    ComponentType.source: source\n",
     "}"
    ]
   },
@@ -148,7 +148,7 @@
     }
    ],
    "source": [
-    "print(pd.DataFrame(input_data[\"sym_load\"]))"
+    "print(pd.DataFrame(input_data[ComponentType.sym_load]))"
    ]
   },
   {
@@ -296,9 +296,9 @@
    ],
    "source": [
     "print(\"------node result------\")\n",
-    "print(pd.DataFrame(output_data[\"node\"]))\n",
+    "print(pd.DataFrame(output_data[ComponentType.node]))\n",
     "print(\"------line result------\")\n",
-    "print(pd.DataFrame(output_data[\"line\"]))"
+    "print(pd.DataFrame(output_data[ComponentType.line]))"
    ]
   },
   {
@@ -340,12 +340,12 @@
     "    error_tolerance=1e-8,\n",
     "    max_iterations=20,\n",
     "    calculation_method=CalculationMethod.newton_raphson,\n",
-    "    output_component_types=[\"node\"])\n",
+    "    output_component_types=[ComponentType.node])\n",
     "\n",
     "print(\"List of component types in result dataset\")\n",
     "print(list(output_data.keys()))\n",
     "print(\"------node result------\")\n",
-    "print(pd.DataFrame(output_data[\"node\"]))"
+    "print(pd.DataFrame(output_data[ComponentType.node]))"
    ]
   },
   {
@@ -395,7 +395,7 @@
    "source": [
     "output_data = model.calculate_power_flow(symmetric=True, calculation_method=CalculationMethod.linear)\n",
     "print(\"------node result------\")\n",
-    "print(pd.DataFrame(output_data[\"node\"]))"
+    "print(pd.DataFrame(output_data[ComponentType.node]))"
    ]
   },
   {
@@ -440,19 +440,19 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "update_sym_load = initialize_array(\"update\", \"sym_load\", 2)\n",
+    "update_sym_load = initialize_array(DatasetType.update, ComponentType.sym_load, 2)\n",
     "update_sym_load[\"id\"] = [4, 7]  # same ID\n",
     "update_sym_load[\"p_specified\"] = [30e6, 15e6]  # change active power\n",
     "# leave reactive power the same, no need to specify\n",
     "\n",
-    "update_line = initialize_array(\"update\", \"line\", 1)\n",
+    "update_line = initialize_array(DatasetType.update, ComponentType.line, 1)\n",
     "update_line[\"id\"] = [3]  # change line ID 3\n",
     "update_line[\"from_status\"] = [0]  # switch off at from side\n",
     "# leave to-side swiching status the same, no need to specify\n",
     "\n",
     "update_data = {\n",
-    "    \"sym_load\": update_sym_load,\n",
-    "    \"line\": update_line\n",
+    "    ComponentType.sym_load: update_sym_load,\n",
+    "    ComponentType.line: update_line\n",
     "}"
    ]
   },
@@ -537,7 +537,7 @@
    "source": [
     "output_data = model_2.calculate_power_flow()\n",
     "print(\"------line result------\")\n",
-    "print(pd.DataFrame(output_data[\"line\"]))"
+    "print(pd.DataFrame(output_data[ComponentType.line]))"
    ]
   },
   {
@@ -608,7 +608,7 @@
    "outputs": [],
    "source": [
     "load_profile = initialize_array(\n",
-    "    \"update\", \"sym_load\", (10, 2)\n",
+    "    DatasetType.update, ComponentType.sym_load, (10, 2)\n",
     ")  # note the shape of the array, 10 scenarios, 2 objects (loads)\n",
     "# below is an assignment of shape (1, 2) array to shape (10, 2) array\n",
     "# the numpy broadcasting rule ensures that the same object ids are repeated 10 times\n",
@@ -618,7 +618,7 @@
     "# the array is an (10, 2) shape, each row is a scenario, each column is an object\n",
     "load_profile[\"p_specified\"] = [[30e6, 15e6]] * np.linspace(0, 1, 10).reshape(-1, 1)\n",
     "\n",
-    "time_series_mutation = {\"sym_load\": load_profile}\n",
+    "time_series_mutation = {ComponentType.sym_load: load_profile}\n",
     "\n",
     "assert_valid_batch_data(input_data=input_data, update_data=time_series_mutation, calculation_type=CalculationType.power_flow)"
    ]
@@ -659,7 +659,7 @@
    ],
    "source": [
     "output_data = model.calculate_power_flow(update_data=time_series_mutation)\n",
-    "print(output_data[\"line\"][\"i_from\"])"
+    "print(output_data[ComponentType.line][\"i_from\"])"
    ]
   },
   {
@@ -700,7 +700,7 @@
     }
    ],
    "source": [
-    "print(pd.DataFrame(output_data[\"line\"][0]))"
+    "print(pd.DataFrame(output_data[ComponentType.line][0]))"
    ]
   },
   {
@@ -730,7 +730,7 @@
     }
    ],
    "source": [
-    "print(output_data[\"line\"][\"i_from\"][:,0])"
+    "print(output_data[ComponentType.line][\"i_from\"][:,0])"
    ]
   },
   {
@@ -762,7 +762,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "line_profile = initialize_array(\"update\", \"line\", (3, 3))  # 3 scenarios, 3 objects (lines)\n",
+    "line_profile = initialize_array(DatasetType.update, ComponentType.line, (3, 3))  # 3 scenarios, 3 objects (lines)\n",
     "# below the same broadcasting trick\n",
     "line_profile[\"id\"] = [[3, 5, 8]]\n",
     "# fully specify the status of all lines, even it is the same as the base scenario\n",
@@ -777,7 +777,7 @@
     "    [1, 1, 0]\n",
     "]\n",
     "\n",
-    "n_min_1_mutation_update_all = {\"line\": line_profile}\n",
+    "n_min_1_mutation_update_all = {ComponentType.line: line_profile}\n",
     "\n",
     "assert_valid_batch_data(input_data=input_data, update_data=n_min_1_mutation_update_all, calculation_type=CalculationType.power_flow)"
    ]
@@ -809,7 +809,7 @@
    ],
    "source": [
     "output_data = model.calculate_power_flow(update_data=n_min_1_mutation_update_all)\n",
-    "print(output_data[\"line\"][\"i_from\"])"
+    "print(output_data[ComponentType.line][\"i_from\"])"
    ]
   },
   {
@@ -830,14 +830,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "line_profile = initialize_array(\"update\", \"line\", (3, 1))  # 3 scenarios, 1 object mutation per scenario\n",
+    "line_profile = initialize_array(DatasetType.update, ComponentType.line, (3, 1))  # 3 scenarios, 1 object mutation per scenario\n",
     "# for each mutation, only one object is specified\n",
     "line_profile[\"id\"] = [[3], [5], [8]]\n",
     "# specify only the changed status (switch off) of one line\n",
     "line_profile[\"from_status\"] = [[0], [0], [0]]\n",
     "line_profile[\"to_status\"] = [[0], [0], [0]]\n",
     "\n",
-    "n_min_1_mutation_update_specific = {\"line\": line_profile}\n",
+    "n_min_1_mutation_update_specific = {ComponentType.line: line_profile}\n",
     "\n",
     "assert_valid_batch_data(input_data=input_data, update_data=n_min_1_mutation_update_specific, calculation_type=CalculationType.power_flow)"
    ]
@@ -869,7 +869,7 @@
    ],
    "source": [
     "output_data = model.calculate_power_flow(update_data=n_min_1_mutation_update_specific)\n",
-    "print(output_data[\"line\"][\"i_from\"])"
+    "print(output_data[ComponentType.line][\"i_from\"])"
    ]
   },
   {
@@ -957,11 +957,11 @@
     "from power_grid_model.errors import PowerGridError, ConflictVoltage\n",
     "\n",
     "# node\n",
-    "node_error = initialize_array(\"input\", \"node\", 2)\n",
+    "node_error = initialize_array(DatasetType.input, ComponentType.node, 2)\n",
     "node_error[\"id\"] = [1, 2]\n",
     "node_error[\"u_rated\"] = [10.5e3, 150.0e3]  # different rated voltages\n",
     "# line\n",
-    "line_error = initialize_array(\"input\", \"line\", 1)\n",
+    "line_error = initialize_array(DatasetType.input, ComponentType.line, 1)\n",
     "line_error[\"id\"] = [3]\n",
     "line_error[\"from_node\"] = [1]\n",
     "line_error[\"to_node\"] = [2]\n",
@@ -974,8 +974,8 @@
     "line_error[\"i_n\"] = [1000]\n",
     "\n",
     "error_data = {\n",
-    "    \"node\": node_error,\n",
-    "    \"line\": line_error\n",
+    "    ComponentType.node: node_error,\n",
+    "    ComponentType.line: line_error\n",
     "}\n",
     "\n",
     "try:\n",
@@ -1017,13 +1017,13 @@
    "source": [
     "from power_grid_model.errors import IDNotFound\n",
     "\n",
-    "line_update_error = initialize_array(\"update\", \"line\", 1)\n",
+    "line_update_error = initialize_array(DatasetType.update, ComponentType.line, 1)\n",
     "line_update_error[\"id\"] = [12345]  # non-existing\n",
     "line_update_error[\"from_status\"] = [1]\n",
     "\n",
     "\n",
     "try:\n",
-    "    model.update(update_data={\"line\": line_update_error})\n",
+    "    model.update(update_data={ComponentType.line: line_update_error})\n",
     "except IDNotFound as e:\n",
     "    print(e)"
    ]
@@ -1096,8 +1096,8 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "time_series_mutation[\"sym_load\"][\"id\"][3] = 1000  # unknown id\n",
-    "time_series_mutation[\"sym_load\"][\"p_specified\"][7] = 1e100  # large power\n"
+    "time_series_mutation[ComponentType.sym_load][\"id\"][3] = 1000  # unknown id\n",
+    "time_series_mutation[ComponentType.sym_load][\"p_specified\"][7] = 1e100  # large power\n"
    ]
   },
   {
@@ -1180,12 +1180,12 @@
     "\n",
     "# print node data for u_pu, note that the data is rubbish for scenario 3 and 7\n",
     "print(\"Node data with invalid results\")\n",
-    "print(output_data[\"node\"][\"u_pu\"])\n",
+    "print(output_data[ComponentType.node][\"u_pu\"])\n",
     "\n",
     "# we can print the data with only succeeded scenarios\n",
     "e = model.batch_error\n",
     "print(\"Node data with only valid results\")\n",
-    "print(output_data[\"node\"][\"u_pu\"][e.succeeded_scenarios])"
+    "print(output_data[ComponentType.node][\"u_pu\"][e.succeeded_scenarios])"
    ]
   },
   {
diff --git a/docs/examples/Serialization Example.ipynb b/docs/examples/Serialization Example.ipynb
index 70bc76d7d..201324c0d 100644
--- a/docs/examples/Serialization Example.ipynb
+++ b/docs/examples/Serialization Example.ipynb
@@ -30,7 +30,7 @@
     "    # suppress warning about pyarrow as future required dependency\n",
     "    from pandas import DataFrame\n",
     "\n",
-    "from power_grid_model import PowerGridModel\n",
+    "from power_grid_model import PowerGridModel, ComponentType\n",
     "from power_grid_model.utils import json_deserialize, json_serialize"
    ]
   },
@@ -185,7 +185,7 @@
     "dataset = json_deserialize(data)\n",
     "\n",
     "print(\"components:\", dataset.keys())\n",
-    "display(DataFrame(dataset[\"node\"]))"
+    "display(DataFrame(dataset[ComponentType.node]))"
    ]
   },
   {
@@ -285,7 +285,7 @@
     "model = PowerGridModel(dataset)\n",
     "output = model.calculate_power_flow()\n",
     "\n",
-    "display(DataFrame(output[\"node\"]))"
+    "display(DataFrame(output[ComponentType.node]))"
    ]
   },
   {
@@ -587,9 +587,9 @@
     "output_data_compact = msgpack_deserialize(msgpack_data_compact)\n",
     "\n",
     "print(\"----Node result from not compact data----\")\n",
-    "print(DataFrame(output_data_not_compact[\"node\"]))\n",
+    "print(DataFrame(output_data_not_compact[ComponentType.node]))\n",
     "print(\"----Node result from compact data----\")\n",
-    "print(DataFrame(output_data_compact[\"node\"]))"
+    "print(DataFrame(output_data_compact[ComponentType.node]))"
    ]
   }
  ],
diff --git a/docs/examples/Short Circuit Example.ipynb b/docs/examples/Short Circuit Example.ipynb
index 64fb7219d..3fe6ca06d 100644
--- a/docs/examples/Short Circuit Example.ipynb
+++ b/docs/examples/Short Circuit Example.ipynb
@@ -54,7 +54,7 @@
     "    # suppress warning about pyarrow as future required dependency\n",
     "    import pandas as pd\n",
     "\n",
-    "from power_grid_model import LoadGenType\n",
+    "from power_grid_model import LoadGenType, ComponentType, DatasetType\n",
     "from power_grid_model import PowerGridModel, CalculationMethod, CalculationType, FaultType, FaultPhase, ShortCircuitVoltageScaling\n",
     "from power_grid_model import initialize_array"
    ]
@@ -82,12 +82,12 @@
    "outputs": [],
    "source": [
     "# node\n",
-    "node = initialize_array(\"input\", \"node\", 3)\n",
+    "node = initialize_array(DatasetType.input, ComponentType.node, 3)\n",
     "node[\"id\"] = np.array([1, 2, 6])\n",
     "node[\"u_rated\"] = [10.5e3, 10.5e3, 10.5e3]\n",
     "\n",
     "# line\n",
-    "line = initialize_array(\"input\", \"line\", 3)\n",
+    "line = initialize_array(DatasetType.input, ComponentType.line, 3)\n",
     "line[\"id\"] = [3, 5, 8]\n",
     "line[\"from_node\"] = [1, 2, 1]\n",
     "line[\"to_node\"] = [2, 6, 6]\n",
@@ -100,7 +100,7 @@
     "line[\"i_n\"] = [1000, 1000, 1000]\n",
     "\n",
     "# load\n",
-    "sym_load = initialize_array(\"input\", \"sym_load\", 2)\n",
+    "sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 2)\n",
     "sym_load[\"id\"] = [4, 7]\n",
     "sym_load[\"node\"] = [2, 6]\n",
     "sym_load[\"status\"] = [1, 1]\n",
@@ -109,14 +109,14 @@
     "sym_load[\"q_specified\"] = [5e6, 2e6]\n",
     "\n",
     "# source\n",
-    "source = initialize_array(\"input\", \"source\", 1)\n",
+    "source = initialize_array(DatasetType.input, ComponentType.source, 1)\n",
     "source[\"id\"] = [10]\n",
     "source[\"node\"] = [1]\n",
     "source[\"status\"] = [1]\n",
     "source[\"u_ref\"] = [1.0]\n",
     "\n",
     "# fault\n",
-    "fault = initialize_array(\"input\", \"fault\", 1)\n",
+    "fault = initialize_array(DatasetType.input, ComponentType.fault, 1)\n",
     "fault[\"id\"] = [11]\n",
     "fault[\"status\"] = [1]\n",
     "fault[\"fault_object\"] = [6]\n",
@@ -127,11 +127,11 @@
     "\n",
     "# all\n",
     "input_data = {\n",
-    "    \"node\": node,\n",
-    "    \"line\": line,\n",
-    "    \"sym_load\": sym_load,\n",
-    "    \"source\": source,\n",
-    "    \"fault\": fault\n",
+    "    ComponentType.node: node,\n",
+    "    ComponentType.line: line,\n",
+    "    ComponentType.sym_load: sym_load,\n",
+    "    ComponentType.source: source,\n",
+    "    ComponentType.fault: fault\n",
     "}"
    ]
   },
@@ -284,19 +284,19 @@
    ],
    "source": [
     "print(\"\\n------fault result: id------\")\n",
-    "print(output_data[\"fault\"][\"id\"])\n",
+    "print(output_data[ComponentType.fault][\"id\"])\n",
     "print(\"------fault result: i_f------\")\n",
-    "print(output_data[\"fault\"][\"i_f\"])\n",
+    "print(output_data[ComponentType.fault][\"i_f\"])\n",
     "\n",
     "print(\"\\n------node result: id------\")\n",
-    "print(output_data[\"node\"][\"id\"])\n",
+    "print(output_data[ComponentType.node][\"id\"])\n",
     "print(\"------node result: u_pu------\")\n",
-    "print(output_data[\"node\"][\"u_pu\"])\n",
+    "print(output_data[ComponentType.node][\"u_pu\"])\n",
     "\n",
     "print(\"\\n------line result: id------\")\n",
-    "print(output_data[\"line\"][\"id\"])\n",
+    "print(output_data[ComponentType.line][\"id\"])\n",
     "print(\"------line result: u_pu------\")\n",
-    "print(output_data[\"line\"][\"i_from\"])\n"
+    "print(output_data[ComponentType.line][\"i_from\"])\n"
    ]
   },
   {
diff --git a/docs/examples/State Estimation Example.ipynb b/docs/examples/State Estimation Example.ipynb
index ecb1218c8..9366d6f43 100644
--- a/docs/examples/State Estimation Example.ipynb
+++ b/docs/examples/State Estimation Example.ipynb
@@ -49,7 +49,7 @@
     "    # suppress warning about pyarrow as future required dependency\n",
     "    import pandas as pd\n",
     "\n",
-    "from power_grid_model import LoadGenType\n",
+    "from power_grid_model import LoadGenType, DatasetType, ComponentType\n",
     "from power_grid_model import PowerGridModel, CalculationMethod, CalculationType, MeasuredTerminalType\n",
     "from power_grid_model import initialize_array"
    ]
@@ -77,12 +77,12 @@
    "outputs": [],
    "source": [
     "# node\n",
-    "node = initialize_array(\"input\", \"node\", 3)\n",
+    "node = initialize_array(DatasetType.input, ComponentType.node, 3)\n",
     "node[\"id\"] = [1, 2, 6]\n",
     "node[\"u_rated\"] = [10.5e3, 10.5e3, 10.5e3]\n",
     "\n",
     "# line\n",
-    "line = initialize_array(\"input\", \"line\", 3)\n",
+    "line = initialize_array(DatasetType.input, ComponentType.line, 3)\n",
     "line[\"id\"] = [3, 5, 8]\n",
     "line[\"from_node\"] = [1, 2, 1]\n",
     "line[\"to_node\"] = [2, 6, 6]\n",
@@ -95,7 +95,7 @@
     "line[\"i_n\"] = [1000, 1000, 1000]\n",
     "\n",
     "# load\n",
-    "sym_load = initialize_array(\"input\", \"sym_load\", 2)\n",
+    "sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 2)\n",
     "sym_load[\"id\"] = [4, 7]\n",
     "sym_load[\"node\"] = [2, 6]\n",
     "sym_load[\"status\"] = [1, 1]\n",
@@ -104,21 +104,21 @@
     "sym_load[\"q_specified\"] = [5e6, 2e6]\n",
     "\n",
     "# source\n",
-    "source = initialize_array(\"input\", \"source\", 1)\n",
+    "source = initialize_array(DatasetType.input, ComponentType.source, 1)\n",
     "source[\"id\"] = [10]\n",
     "source[\"node\"] = [1]\n",
     "source[\"status\"] = [1]\n",
     "source[\"u_ref\"] = [1.0]\n",
     "\n",
     "# voltage sensor\n",
-    "sym_voltage_sensor = initialize_array(\"input\", \"sym_voltage_sensor\", 3)\n",
+    "sym_voltage_sensor = initialize_array(DatasetType.input, ComponentType.sym_voltage_sensor, 3)\n",
     "sym_voltage_sensor[\"id\"] = [11, 12, 13]\n",
     "sym_voltage_sensor[\"measured_object\"] = [1, 2, 6]\n",
     "sym_voltage_sensor[\"u_sigma\"] = [1.0, 1.0, 1.0]\n",
     "sym_voltage_sensor[\"u_measured\"] = [10489.37, 9997.32, 10102.01]\n",
     "\n",
     "# power sensor\n",
-    "sym_power_sensor = initialize_array(\"input\", \"sym_power_sensor\", 8)\n",
+    "sym_power_sensor = initialize_array(DatasetType.input, ComponentType.sym_power_sensor, 8)\n",
     "sym_power_sensor[\"id\"] = [14, 15, 16, 17, 18, 19, 20, 21]\n",
     "sym_power_sensor[\"measured_object\"] = [3, 3, 5, 5, 8, 8, 4, 6]\n",
     "sym_power_sensor[\"measured_terminal_type\"] = [\n",
@@ -137,12 +137,12 @@
     "\n",
     "# all\n",
     "input_data = {\n",
-    "    \"node\": node,\n",
-    "    \"line\": line,\n",
-    "    \"sym_load\": sym_load,\n",
-    "    \"source\": source,\n",
-    "    \"sym_voltage_sensor\": sym_voltage_sensor,\n",
-    "    \"sym_power_sensor\": sym_power_sensor,\n",
+    "    ComponentType.node: node,\n",
+    "    ComponentType.line: line,\n",
+    "    ComponentType.sym_load: sym_load,\n",
+    "    ComponentType.source: source,\n",
+    "    ComponentType.sym_voltage_sensor: sym_voltage_sensor,\n",
+    "    ComponentType.sym_power_sensor: sym_power_sensor,\n",
     "}"
    ]
   },
@@ -502,13 +502,13 @@
    ],
    "source": [
     "print(\"Node result\")\n",
-    "display(pd.DataFrame(output_data[\"node\"]))\n",
+    "display(pd.DataFrame(output_data[ComponentType.node]))\n",
     "\n",
     "print(\"Line result\")\n",
-    "display(pd.DataFrame(output_data[\"line\"]))\n",
+    "display(pd.DataFrame(output_data[ComponentType.line]))\n",
     "\n",
     "print(\"Sym_load result\")\n",
-    "display(pd.DataFrame(output_data[\"sym_load\"]))"
+    "display(pd.DataFrame(output_data[ComponentType.sym_load]))"
    ]
   },
   {
@@ -626,7 +626,7 @@
     "output_data_NR = model.calculate_state_estimation(symmetric=True, calculation_method=CalculationMethod.newton_raphson)\n",
     "\n",
     "print(\"Node result\")\n",
-    "display(pd.DataFrame(output_data_NR[\"node\"]))"
+    "display(pd.DataFrame(output_data_NR[ComponentType.node]))"
    ]
   },
   {
@@ -728,7 +728,7 @@
    ],
    "source": [
     "# power sensor\n",
-    "sym_power_sensor2 = initialize_array(\"input\", \"sym_power_sensor\", 8)\n",
+    "sym_power_sensor2 = initialize_array(DatasetType.input, ComponentType.sym_power_sensor, 8)\n",
     "sym_power_sensor2[\"id\"] = [14, 15, 16, 17, 18, 19, 20, 21]\n",
     "sym_power_sensor2[\"measured_object\"] = [3, 3, 5, 5, 8, 8, 4, 6]\n",
     "sym_power_sensor2[\"measured_terminal_type\"] = [\n",
@@ -748,18 +748,18 @@
     "\n",
     "# all\n",
     "input_data2 = {\n",
-    "    \"node\": node,\n",
-    "    \"line\": line,\n",
-    "    \"sym_load\": sym_load,\n",
-    "    \"source\": source,\n",
-    "    \"sym_voltage_sensor\": sym_voltage_sensor,\n",
-    "    \"sym_power_sensor\": sym_power_sensor2,\n",
+    "    ComponentType.node: node,\n",
+    "    ComponentType.line: line,\n",
+    "    ComponentType.sym_load: sym_load,\n",
+    "    ComponentType.source: source,\n",
+    "    ComponentType.sym_voltage_sensor: sym_voltage_sensor,\n",
+    "    ComponentType.sym_power_sensor: sym_power_sensor2,\n",
     "}\n",
     "\n",
     "model2 = PowerGridModel(input_data2)\n",
     "output_data_NR2 = model2.calculate_state_estimation(symmetric=True, calculation_method=CalculationMethod.newton_raphson)\n",
     "print(\"Node result\")\n",
-    "display(pd.DataFrame(output_data_NR2[\"node\"]))"
+    "display(pd.DataFrame(output_data_NR2[ComponentType.node]))"
    ]
   },
   {
@@ -883,21 +883,21 @@
     }
    ],
    "source": [
-    "sym_voltage_sensor_update = initialize_array(\"update\", \"sym_voltage_sensor\", 1)\n",
+    "sym_voltage_sensor_update = initialize_array(DatasetType.update, ComponentType.sym_voltage_sensor, 1)\n",
     "# for each mutation, only one object is specified\n",
     "sym_voltage_sensor_update[\"id\"] = 13\n",
     "sym_voltage_sensor_update[\"u_sigma\"] = np.inf  # disable this sensor\n",
     "\n",
-    "sym_power_sensor_update = initialize_array(\"update\", \"sym_power_sensor\", 1)\n",
+    "sym_power_sensor_update = initialize_array(DatasetType.update, ComponentType.sym_power_sensor, 1)\n",
     "sym_power_sensor_update[\"id\"] = 21\n",
     "sym_power_sensor_update[\"power_sigma\"] = np.inf  # disable this sensor\n",
     "\n",
-    "update_data = {\"sym_voltage_sensor\": sym_voltage_sensor_update, \"sym_power_sensor\": sym_power_sensor_update}\n",
+    "update_data = {ComponentType.sym_voltage_sensor: sym_voltage_sensor_update, ComponentType.sym_power_sensor: sym_power_sensor_update}\n",
     "\n",
     "# Permanent update\n",
     "model.update(update_data=update_data)\n",
     "output_data = model.calculate_state_estimation()\n",
-    "display(pd.DataFrame(output_data[\"node\"]))\n",
+    "display(pd.DataFrame(output_data[ComponentType.node]))\n",
     "\n",
     "# fully reinstigate the original model to prevent this cell from influencing re-runs. A model update would be sufficient as well.\n",
     "model = PowerGridModel(input_data)"
@@ -933,15 +933,15 @@
    "source": [
     "from power_grid_model.errors import PowerGridError\n",
     "\n",
-    "sym_voltage_sensor_update = initialize_array(\"update\", \"sym_voltage_sensor\", 3)\n",
+    "sym_voltage_sensor_update = initialize_array(DatasetType.update, ComponentType.sym_voltage_sensor, 3)\n",
     "sym_voltage_sensor_update[\"id\"] = sym_voltage_sensor[\"id\"]\n",
     "sym_voltage_sensor_update[\"u_sigma\"] = np.inf  # disable all sensors\n",
     "\n",
-    "sym_power_sensor_update = initialize_array(\"update\", \"sym_power_sensor\", 8)\n",
+    "sym_power_sensor_update = initialize_array(DatasetType.update, ComponentType.sym_power_sensor, 8)\n",
     "sym_power_sensor_update[\"id\"] = sym_power_sensor[\"id\"]\n",
     "sym_power_sensor_update[\"power_sigma\"] = np.inf  # disable all sensors\n",
     "\n",
-    "update_data = {\"sym_voltage_sensor\": sym_voltage_sensor_update, \"sym_power_sensor\": sym_power_sensor_update}\n",
+    "update_data = {ComponentType.sym_voltage_sensor: sym_voltage_sensor_update, ComponentType.sym_power_sensor: sym_power_sensor_update}\n",
     "\n",
     "try:\n",
     "    # Permanent update\n",
@@ -984,7 +984,7 @@
    "outputs": [],
    "source": [
     "sym_voltage_sensor_update = initialize_array(\n",
-    "    \"update\", \"sym_voltage_sensor\", (4, 3)\n",
+    "    DatasetType.update, ComponentType.sym_voltage_sensor, (4, 3)\n",
     ")  # 4 scenarios, 3 objects per scenario\n",
     "# for each mutation, only one object is specified\n",
     "sym_voltage_sensor_update[\"id\"] = [[11, 12, 13]] * 4\n",
@@ -996,7 +996,7 @@
     "]\n",
     "sym_voltage_sensor_update[\"u_sigma\"][2, 2] = np.inf  # disable the third sensor of the third scenario\n",
     "\n",
-    "sym_power_sensor_update = initialize_array(\"update\", \"sym_power_sensor\", (4, 1))\n",
+    "sym_power_sensor_update = initialize_array(DatasetType.update, ComponentType.sym_power_sensor, (4, 1))\n",
     "sym_power_sensor_update[\"id\"] = [21]\n",
     "sym_power_sensor_update[\"power_sigma\"] = [\n",
     "    [1.0e3],\n",
@@ -1005,7 +1005,7 @@
     "    [np.inf],  # disables this sensor on the last scenario\n",
     "]\n",
     "\n",
-    "update_data = {\"sym_voltage_sensor\": sym_voltage_sensor_update, \"sym_power_sensor\": sym_power_sensor_update}"
+    "update_data = {ComponentType.sym_voltage_sensor: sym_voltage_sensor_update, ComponentType.sym_power_sensor: sym_power_sensor_update}"
    ]
   },
   {
@@ -1065,7 +1065,7 @@
     "    max_iterations=20,\n",
     "    calculation_method=CalculationMethod.iterative_linear,\n",
     ")\n",
-    "print(batch_output_data[\"node\"][\"u\"])"
+    "print(batch_output_data[ComponentType.node][\"u\"])"
    ]
   }
  ],
diff --git a/docs/examples/Transformer Examples.ipynb b/docs/examples/Transformer Examples.ipynb
index 2b232e285..e2faaa244 100644
--- a/docs/examples/Transformer Examples.ipynb
+++ b/docs/examples/Transformer Examples.ipynb
@@ -44,7 +44,7 @@
     "    # suppress warning about pyarrow as future required dependency\n",
     "    import pandas as pd\n",
     "\n",
-    "from power_grid_model import LoadGenType\n",
+    "from power_grid_model import LoadGenType, DatasetType, ComponentType\n",
     "from power_grid_model import (\n",
     "    PowerGridModel,\n",
     "    CalculationMethod,\n",
@@ -77,12 +77,12 @@
    "outputs": [],
    "source": [
     "# node\n",
-    "node = initialize_array(\"input\", \"node\", 2)\n",
+    "node = initialize_array(DatasetType.input, ComponentType.node, 2)\n",
     "node[\"id\"] = np.array([2, 4])\n",
     "node[\"u_rated\"] = [1e4, 4e2]\n",
     "\n",
     "# load\n",
-    "sym_load = initialize_array(\"input\", \"sym_load\", 1)\n",
+    "sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 1)\n",
     "sym_load[\"id\"] = [5]\n",
     "sym_load[\"node\"] = [4]\n",
     "sym_load[\"status\"] = [1]\n",
@@ -91,14 +91,14 @@
     "sym_load[\"q_specified\"] = [5e3]\n",
     "\n",
     "# source\n",
-    "source = initialize_array(\"input\", \"source\", 1)\n",
+    "source = initialize_array(DatasetType.input, ComponentType.source, 1)\n",
     "source[\"id\"] = [1]\n",
     "source[\"node\"] = [2]\n",
     "source[\"status\"] = [1]\n",
     "source[\"u_ref\"] = [1.0]\n",
     "\n",
     "# transformer\n",
-    "transformer = initialize_array(\"input\", \"transformer\", 1)\n",
+    "transformer = initialize_array(DatasetType.input, ComponentType.transformer, 1)\n",
     "transformer[\"id\"] = [3]\n",
     "transformer[\"from_node\"] = [2]\n",
     "transformer[\"to_node\"] = [4]\n",
@@ -121,7 +121,7 @@
     "transformer[\"tap_size\"] = [100]\n",
     "\n",
     "# all\n",
-    "input_data = {\"node\": node, \"transformer\": transformer, \"sym_load\": sym_load, \"source\": source}"
+    "input_data = {ComponentType.node: node, ComponentType.transformer: transformer, ComponentType.sym_load: sym_load, ComponentType.source: source}"
    ]
   },
   {
@@ -156,7 +156,7 @@
     }
    ],
    "source": [
-    "print(pd.DataFrame(input_data[\"transformer\"]))"
+    "print(pd.DataFrame(input_data[ComponentType.transformer]))"
    ]
   },
   {
@@ -208,7 +208,7 @@
     "\n",
     "# result dataset\n",
     "print(\"------node result------\")\n",
-    "print(pd.DataFrame(output_data[\"node\"]))"
+    "print(pd.DataFrame(output_data[ComponentType.node]))"
    ]
   },
   {
@@ -248,14 +248,14 @@
    ],
    "source": [
     "# voltage sensor\n",
-    "sym_voltage_sensor = initialize_array(\"input\", \"sym_voltage_sensor\", 2)\n",
+    "sym_voltage_sensor = initialize_array(DatasetType.input, ComponentType.sym_voltage_sensor, 2)\n",
     "sym_voltage_sensor[\"id\"] = [6, 7]\n",
     "sym_voltage_sensor[\"measured_object\"] = [2, 4]\n",
     "sym_voltage_sensor[\"u_sigma\"] = [1.0, 1.0]\n",
     "sym_voltage_sensor[\"u_measured\"] = [1e5, 4e2]\n",
     "\n",
     "# power sensor\n",
-    "sym_power_sensor = initialize_array(\"input\", \"sym_power_sensor\", 2)\n",
+    "sym_power_sensor = initialize_array(DatasetType.input, ComponentType.sym_power_sensor, 2)\n",
     "sym_power_sensor[\"id\"] = [8, 9]\n",
     "sym_power_sensor[\"measured_object\"] = [3, 3]\n",
     "sym_power_sensor[\"measured_terminal_type\"] = [\n",
@@ -268,12 +268,12 @@
     "\n",
     "# use components from former input dataset cell.\n",
     "input_data2 = {\n",
-    "    \"node\": node,\n",
-    "    \"transformer\": transformer,\n",
-    "    \"sym_load\": sym_load,\n",
-    "    \"source\": source,\n",
-    "    \"sym_voltage_sensor\": sym_voltage_sensor,\n",
-    "    \"sym_power_sensor\": sym_power_sensor,\n",
+    "    ComponentType.node: node,\n",
+    "    ComponentType.transformer: transformer,\n",
+    "    ComponentType.sym_load: sym_load,\n",
+    "    ComponentType.source: source,\n",
+    "    ComponentType.sym_voltage_sensor: sym_voltage_sensor,\n",
+    "    ComponentType.sym_power_sensor: sym_power_sensor,\n",
     "}\n",
     "\n",
     "# validation (optional)\n",
@@ -291,7 +291,7 @@
     "\n",
     "# result dataset\n",
     "print(\"------node result------\")\n",
-    "print(pd.DataFrame(output_data2[\"node\"]))"
+    "print(pd.DataFrame(output_data2[ComponentType.node]))"
    ]
   },
   {
@@ -336,12 +336,12 @@
    "outputs": [],
    "source": [
     "# node\n",
-    "node = initialize_array(\"input\", \"node\", 3)\n",
+    "node = initialize_array(DatasetType.input, ComponentType.node, 3)\n",
     "node[\"id\"] = np.array([2, 4, 6])\n",
     "node[\"u_rated\"] = [1e4, 1e2, 1e2]\n",
     "\n",
     "# load\n",
-    "sym_load = initialize_array(\"input\", \"sym_load\", 2)\n",
+    "sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 2)\n",
     "sym_load[\"id\"] = [5, 7]\n",
     "sym_load[\"node\"] = [4, 6]\n",
     "sym_load[\"status\"] = [1]\n",
@@ -350,14 +350,14 @@
     "sym_load[\"q_specified\"] = [5e3, 5e3]\n",
     "\n",
     "# source\n",
-    "source = initialize_array(\"input\", \"source\", 1)\n",
+    "source = initialize_array(DatasetType.input, ComponentType.source, 1)\n",
     "source[\"id\"] = [1]\n",
     "source[\"node\"] = [2]\n",
     "source[\"status\"] = [1]\n",
     "source[\"u_ref\"] = [1.0]\n",
     "\n",
     "# three-winding transformer\n",
-    "three_winding_transformer = initialize_array(\"input\", \"three_winding_transformer\", 1)\n",
+    "three_winding_transformer = initialize_array(DatasetType.input, ComponentType.three_winding_transformer, 1)\n",
     "three_winding_transformer[\"id\"] = [3]\n",
     "three_winding_transformer[\"node_1\"] = [2]\n",
     "three_winding_transformer[\"node_2\"] = [4]\n",
@@ -393,10 +393,10 @@
     "\n",
     "# all\n",
     "input_data3 = {\n",
-    "    \"node\": node,\n",
-    "    \"three_winding_transformer\": three_winding_transformer,\n",
-    "    \"sym_load\": sym_load,\n",
-    "    \"source\": source,\n",
+    "    ComponentType.node: node,\n",
+    "    ComponentType.three_winding_transformer: three_winding_transformer,\n",
+    "    ComponentType.sym_load: sym_load,\n",
+    "    ComponentType.source: source,\n",
     "}"
    ]
   },
@@ -447,7 +447,7 @@
     "\n",
     "# result dataset\n",
     "print(\"------node result------\")\n",
-    "print(pd.DataFrame(output_data3[\"node\"]))"
+    "print(pd.DataFrame(output_data3[ComponentType.node]))"
    ]
   },
   {
@@ -488,14 +488,14 @@
    ],
    "source": [
     "# voltage sensor\n",
-    "sym_voltage_sensor = initialize_array(\"input\", \"sym_voltage_sensor\", 3)\n",
+    "sym_voltage_sensor = initialize_array(DatasetType.input, ComponentType.sym_voltage_sensor, 3)\n",
     "sym_voltage_sensor[\"id\"] = [8, 9, 10]\n",
     "sym_voltage_sensor[\"measured_object\"] = [2, 4, 6]\n",
     "sym_voltage_sensor[\"u_sigma\"] = [1.0, 1.0, 1.0]\n",
     "sym_voltage_sensor[\"u_measured\"] = [1e4, 1e2, 1e2]\n",
     "\n",
     "# power sensor\n",
-    "sym_power_sensor = initialize_array(\"input\", \"sym_power_sensor\", 3)\n",
+    "sym_power_sensor = initialize_array(DatasetType.input, ComponentType.sym_power_sensor, 3)\n",
     "sym_power_sensor[\"id\"] = [11, 12, 13]\n",
     "sym_power_sensor[\"measured_object\"] = [3, 3, 3]\n",
     "sym_power_sensor[\"measured_terminal_type\"] = [\n",
@@ -509,12 +509,12 @@
     "\n",
     "# use components from the one-time power flow calculation with three-winding transformer\n",
     "input_data4 = {\n",
-    "    \"node\": node,\n",
-    "    \"three_winding_transformer\": three_winding_transformer,\n",
-    "    \"sym_load\": sym_load,\n",
-    "    \"source\": source,\n",
-    "    \"sym_voltage_sensor\": sym_voltage_sensor,\n",
-    "    \"sym_power_sensor\": sym_power_sensor,\n",
+    "    ComponentType.node: node,\n",
+    "    ComponentType.three_winding_transformer: three_winding_transformer,\n",
+    "    ComponentType.sym_load: sym_load,\n",
+    "    ComponentType.source: source,\n",
+    "    ComponentType.sym_voltage_sensor: sym_voltage_sensor,\n",
+    "    ComponentType.sym_power_sensor: sym_power_sensor,\n",
     "}\n",
     "\n",
     "# validation (optional)\n",
@@ -532,7 +532,7 @@
     "\n",
     "# result dataset\n",
     "print(\"------three-winding transformer result------\")\n",
-    "print(pd.DataFrame(output_data4[\"three_winding_transformer\"]))"
+    "print(pd.DataFrame(output_data4[ComponentType.three_winding_transformer]))"
    ]
   },
   {
@@ -573,12 +573,12 @@
    "outputs": [],
    "source": [
     "# node\n",
-    "node = initialize_array(\"input\", \"node\", 3)\n",
+    "node = initialize_array(DatasetType.input, ComponentType.node, 3)\n",
     "node[\"id\"] = [2, 4, 6]\n",
     "node[\"u_rated\"] = [1e4, 4e2, 4e2]\n",
     "\n",
     "# load\n",
-    "sym_load = initialize_array(\"input\", \"sym_load\", 1)\n",
+    "sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 1)\n",
     "sym_load[\"id\"] = [7]\n",
     "sym_load[\"node\"] = [6]\n",
     "sym_load[\"status\"] = [1]\n",
@@ -587,14 +587,14 @@
     "sym_load[\"q_specified\"] = [5e3]\n",
     "\n",
     "# source\n",
-    "source = initialize_array(\"input\", \"source\", 1)\n",
+    "source = initialize_array(DatasetType.input, ComponentType.source, 1)\n",
     "source[\"id\"] = [1]\n",
     "source[\"node\"] = [2]\n",
     "source[\"status\"] = [1]\n",
     "source[\"u_ref\"] = [1.0]\n",
     "\n",
     "# line\n",
-    "line = initialize_array(\"input\", \"line\", 1)\n",
+    "line = initialize_array(DatasetType.input, ComponentType.line, 1)\n",
     "line[\"id\"] = [5]\n",
     "line[\"from_node\"] = [4]\n",
     "line[\"to_node\"] = [6]\n",
@@ -606,7 +606,7 @@
     "line[\"tan1\"] = [0.0]\n",
     "\n",
     "# transformer\n",
-    "transformer = initialize_array(\"input\", \"transformer\", 1)\n",
+    "transformer = initialize_array(DatasetType.input, ComponentType.transformer, 1)\n",
     "transformer[\"id\"] = [3]\n",
     "transformer[\"from_node\"] = [2]\n",
     "transformer[\"to_node\"] = [4]\n",
@@ -629,7 +629,7 @@
     "transformer[\"tap_size\"] = [100]\n",
     "\n",
     "# transformer tap regulator\n",
-    "transformer_tap_regulator = initialize_array(\"input\", \"transformer_tap_regulator\", 1)\n",
+    "transformer_tap_regulator = initialize_array(DatasetType.input, ComponentType.transformer_tap_regulator, 1)\n",
     "transformer_tap_regulator[\"id\"] = [8]\n",
     "transformer_tap_regulator[\"regulated_object\"] = [3]\n",
     "transformer_tap_regulator[\"status\"] = [1]\n",
@@ -641,12 +641,12 @@
     "\n",
     "# all\n",
     "input_data5 = {\n",
-    "    \"node\": node,\n",
-    "    \"line\": line,\n",
-    "    \"transformer\": transformer,\n",
-    "    \"sym_load\": sym_load,\n",
-    "    \"source\": source,\n",
-    "    \"transformer_tap_regulator\": transformer_tap_regulator,\n",
+    "    ComponentType.node: node,\n",
+    "    ComponentType.line: line,\n",
+    "    ComponentType.transformer: transformer,\n",
+    "    ComponentType.sym_load: sym_load,\n",
+    "    ComponentType.source: source,\n",
+    "    ComponentType.transformer_tap_regulator: transformer_tap_regulator,\n",
     "}"
    ]
   },
@@ -740,7 +740,7 @@
     "\n",
     "# Both load-side nodes node_4 and node_6 have a voltage below 400 V\n",
     "print(\"------node result------\")\n",
-    "display(pd.DataFrame(output_data5[\"node\"])[[\"id\", \"u\"]])"
+    "display(pd.DataFrame(output_data5[ComponentType.node])[[\"id\", \"u\"]])"
    ]
   },
   {
@@ -883,10 +883,10 @@
     "\n",
     "# the node at the control side of the transformer now has a voltage within the specified voltage band\n",
     "print(\"------node result------\")\n",
-    "display(pd.DataFrame(output_data6[\"node\"])[[\"id\", \"u\"]])\n",
+    "display(pd.DataFrame(output_data6[ComponentType.node])[[\"id\", \"u\"]])\n",
     "\n",
     "print(\"\\n------tap regulator result------\")\n",
-    "display(pd.DataFrame(output_data6[\"transformer_tap_regulator\"]))"
+    "display(pd.DataFrame(output_data6[ComponentType.transformer_tap_regulator]))"
    ]
   },
   {
@@ -1083,14 +1083,14 @@
     }
    ],
    "source": [
-    "transformer_update = initialize_array(\"update\", \"transformer\", (2, 1))\n",
+    "transformer_update = initialize_array(DatasetType.update, ComponentType.transformer, (2, 1))\n",
     "transformer_update[\"id\"] = 3\n",
     "transformer_update[\"tap_pos\"] = [[0], [1]]\n",
     "\n",
-    "update_data = {\"transformer\": transformer_update}\n",
+    "update_data = {ComponentType.transformer: transformer_update}\n",
     "\n",
     "print(\"------transformer batch update------\")\n",
-    "display(pd.DataFrame(update_data[\"transformer\"][:, 0]))\n",
+    "display(pd.DataFrame(update_data[ComponentType.transformer][:, 0]))\n",
     "\n",
     "# power flow batch calculation with automatic tap changing\n",
     "output_data = model5.calculate_power_flow(\n",
@@ -1098,10 +1098,10 @@
     ")\n",
     "\n",
     "print(\"------node_4 batch result------\")\n",
-    "display(pd.DataFrame(output_data[\"node\"][:, 1])[[\"id\", \"u\"]])  # only output node 1\n",
+    "display(pd.DataFrame(output_data[ComponentType.node][:, 1])[[\"id\", \"u\"]])  # only output node 1\n",
     "\n",
     "print(\"\\n------tap regulator batch result------\")\n",
-    "display(pd.DataFrame(output_data[\"transformer_tap_regulator\"][:, 0]))"
+    "display(pd.DataFrame(output_data[ComponentType.transformer_tap_regulator][:, 0]))"
    ]
   },
   {
@@ -1241,10 +1241,10 @@
     "output_data5 = model5.calculate_power_flow(tap_changing_strategy=TapChangingStrategy.max_voltage_tap)\n",
     "\n",
     "print(\"------node result------\")\n",
-    "display(pd.DataFrame(output_data5[\"node\"])[[\"id\", \"u\"]])\n",
+    "display(pd.DataFrame(output_data5[ComponentType.node])[[\"id\", \"u\"]])\n",
     "\n",
     "print(\"\\n------tap regulator result------\")\n",
-    "display(pd.DataFrame(output_data5[\"transformer_tap_regulator\"]))"
+    "display(pd.DataFrame(output_data5[ComponentType.transformer_tap_regulator]))"
    ]
   },
   {
@@ -1384,10 +1384,10 @@
     "output_data5 = model5.calculate_power_flow(tap_changing_strategy=TapChangingStrategy.min_voltage_tap)\n",
     "\n",
     "print(\"------node result------\")\n",
-    "display(pd.DataFrame(output_data5[\"node\"])[[\"id\", \"u\"]])\n",
+    "display(pd.DataFrame(output_data5[ComponentType.node])[[\"id\", \"u\"]])\n",
     "\n",
     "print(\"\\n------tap regulator result------\")\n",
-    "display(pd.DataFrame(output_data5[\"transformer_tap_regulator\"]))"
+    "display(pd.DataFrame(output_data5[ComponentType.transformer_tap_regulator]))"
    ]
   },
   {
@@ -1421,7 +1421,7 @@
     "input_data6 = {component: component_data.copy() for component, component_data in input_data5.items()}\n",
     "\n",
     "# set the regulator's line drop compensation\n",
-    "input_data6[\"transformer_tap_regulator\"][\"line_drop_compensation_r\"] = [10.0]\n",
+    "input_data6[ComponentType.transformer_tap_regulator][\"line_drop_compensation_r\"] = [10.0]\n",
     "\n",
     "# construction\n",
     "model6 = PowerGridModel(input_data=input_data6)"
@@ -1562,10 +1562,10 @@
     "output_data6 = model6.calculate_power_flow(tap_changing_strategy=TapChangingStrategy.any_valid_tap)\n",
     "\n",
     "print(\"------node result------\")\n",
-    "display(pd.DataFrame(output_data6[\"node\"])[[\"id\", \"u\"]])\n",
+    "display(pd.DataFrame(output_data6[ComponentType.node])[[\"id\", \"u\"]])\n",
     "\n",
     "print(\"\\n------tap regulator result------\")\n",
-    "display(pd.DataFrame(output_data6[\"transformer_tap_regulator\"]))"
+    "display(pd.DataFrame(output_data6[ComponentType.transformer_tap_regulator]))"
    ]
   }
  ],
diff --git a/docs/examples/Validation Examples.ipynb b/docs/examples/Validation Examples.ipynb
index 648575a4f..cf3d4c0d7 100644
--- a/docs/examples/Validation Examples.ipynb
+++ b/docs/examples/Validation Examples.ipynb
@@ -41,14 +41,14 @@
     "```python\n",
     "class ValidationError:\n",
     "    \n",
-    "    # Component(s): e.g. \"node\" or [\"node\", \"line\"]\n",
-    "    component: Union[str, List[str]]\n",
+    "    # Component(s): e.g. ComponentType.node or [ComponentType.node, ComponentType.line]\n",
+    "    component: Union[ComponentType, List[ComponentType]]\n",
     "    \n",
-    "    # Field(s): e.g. \"id\" or [\"line_from\", \"line_to\"] or [(\"node\", \"id\"), (\"line\", \"id\")]\n",
-    "    field: Union[str, List[str], List[Tuple[str, str]]]\n",
+    "    # Field(s): e.g. \"id\" or [\"line_from\", \"line_to\"] or [(ComponentType.node, \"id\"), (ComponentType.line, \"id\")]\n",
+    "    field: Union[str, List[str], List[Tuple[ComponentType, str]]]\n",
     "\n",
-    "    # IDs: e.g. [1, 2, 3] or [(\"node\", 1), (\"line\", 1)]\n",
-    "    ids: Union[List[int], List[Tuple[str, int]]] = []    \n",
+    "    # IDs: e.g. [1, 2, 3] or [(ComponentType.node, 1), (ComponentType.line, 1)]\n",
+    "    ids: Union[List[int], List[Tuple[ComponentType, int]]] = []    \n",
     "    \n",
     "```\n",
     "\n",
@@ -62,17 +62,17 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "from power_grid_model import PowerGridModel, initialize_array\n",
+    "from power_grid_model import PowerGridModel, DatasetType, ComponentType, initialize_array\n",
     "\n",
     "# A power grid containing several errors\n",
     "\n",
     "# node\n",
-    "node_error = initialize_array(\"input\", \"node\", 3)\n",
+    "node_error = initialize_array(DatasetType.input, ComponentType.node, 3)\n",
     "node_error[\"id\"] = [1, 2, 3]\n",
     "node_error[\"u_rated\"] = [10.5e3]\n",
     "\n",
     "# line\n",
-    "line_error = initialize_array(\"input\", \"line\", 3)\n",
+    "line_error = initialize_array(DatasetType.input, ComponentType.line, 3)\n",
     "line_error[\"id\"] = [4, 5, 6]\n",
     "line_error[\"from_node\"] = [1, 2, 3]\n",
     "line_error[\"to_node\"] = [2, 3, 4]\n",
@@ -84,7 +84,7 @@
     "line_error[\"tan1\"] = [0.0]\n",
     "\n",
     "# Power Sensor\n",
-    "sensor_error = initialize_array(\"input\", \"sym_power_sensor\", 2)\n",
+    "sensor_error = initialize_array(DatasetType.input, ComponentType.sym_power_sensor, 2)\n",
     "sensor_error[\"id\"] = [6, 7]\n",
     "sensor_error[\"measured_object\"] = [3, 4]\n",
     "sensor_error[\"measured_terminal_type\"] = [0, 2]\n",
@@ -92,7 +92,7 @@
     "sensor_error[\"q_measured\"] = [0]\n",
     "sensor_error[\"power_sigma\"] = [0]\n",
     "\n",
-    "error_data = {\"node\": node_error, \"line\": line_error, \"sym_power_sensor\": sensor_error}"
+    "error_data = {ComponentType.node: node_error, ComponentType.line: line_error, ComponentType.sym_power_sensor: sensor_error}"
    ]
   },
   {
diff --git a/scripts/quick_example.py b/scripts/quick_example.py
index 5686fb3ee..b5cbcefb0 100644
--- a/scripts/quick_example.py
+++ b/scripts/quick_example.py
@@ -4,15 +4,17 @@
 
 import pandas as pd
 
-from power_grid_model import LoadGenType, PowerGridModel, initialize_array
+from power_grid_model import ComponentType, DatasetType, LoadGenType, PowerGridModel, initialize_array
 
 # node
-node = initialize_array("input", "node", 2)
+node = initialize_array(DatasetType.input, ComponentType.node, 2)
+# The following is also supported
+# node = initialize_array("input", "node", 2)
 node["id"] = [1, 2]
 node["u_rated"] = [10.5e3, 10.5e3]
 
 # line
-line = initialize_array("input", "line", 1)
+line = initialize_array(DatasetType.input, ComponentType.line, 1)
 line["id"] = [3]
 line["from_node"] = [1]
 line["to_node"] = [2]
@@ -25,7 +27,7 @@
 line["i_n"] = [1000]
 
 # load
-sym_load = initialize_array("input", "sym_load", 1)
+sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 1)
 sym_load["id"] = [4]
 sym_load["node"] = [2]
 sym_load["status"] = [1]
@@ -34,14 +36,19 @@
 sym_load["q_specified"] = [0.5e6]
 
 # source
-source = initialize_array("input", "source", 1)
+source = initialize_array(DatasetType.input, ComponentType.source, 1)
 source["id"] = [5]
 source["node"] = [1]
 source["status"] = [1]
 source["u_ref"] = [1.0]
 
 # input_data
-input_data = {"node": node, "line": line, "sym_load": sym_load, "source": source}
+input_data = {
+    ComponentType.node: node,
+    ComponentType.line: line,
+    ComponentType.sym_load: sym_load,
+    ComponentType.source: source,
+}
 
 # call constructor
 model = PowerGridModel(input_data, system_frequency=50.0)
@@ -49,6 +56,6 @@
 result = model.calculate_power_flow()
 
 print("Node Input")
-print(pd.DataFrame(input_data["node"]))
+print(pd.DataFrame(input_data[ComponentType.node]))
 print("Node Result")
-print(pd.DataFrame(result["node"]))
+print(pd.DataFrame(result[ComponentType.node]))
diff --git a/scripts/quick_example_batch.py b/scripts/quick_example_batch.py
index 1b6608d04..1889e4e0b 100644
--- a/scripts/quick_example_batch.py
+++ b/scripts/quick_example_batch.py
@@ -5,7 +5,7 @@
 import numpy as np
 import pandas as pd
 
-from power_grid_model import LoadGenType, PowerGridModel, initialize_array
+from power_grid_model import ComponentType, DatasetType, LoadGenType, PowerGridModel, initialize_array
 
 """
 node_1 ---line_3--- node_2 ---line_6--- node_7
@@ -15,12 +15,14 @@
 """
 
 # node
-node = initialize_array("input", "node", 3)
+node = initialize_array(DatasetType.input, ComponentType.node, 3)
+# The following is also supported
+# node = initialize_array("input", "node", 3)
 node["id"] = [1, 2, 7]
 node["u_rated"] = [10.5e3, 10.5e3, 10.5e3]
 
 # line
-line = initialize_array("input", "line", 2)
+line = initialize_array(DatasetType.input, ComponentType.line, 2)
 line["id"] = [3, 6]
 line["from_node"] = [1, 2]
 line["to_node"] = [2, 7]
@@ -36,7 +38,7 @@
 line["tan0"] = [0.0, 0.0]  # zero sequence parameters
 
 # load
-asym_load = initialize_array("input", "asym_load", 2)
+asym_load = initialize_array(DatasetType.input, ComponentType.asym_load, 2)
 asym_load["id"] = [4, 8]
 asym_load["node"] = [2, 7]
 asym_load["status"] = [1, 1]
@@ -47,14 +49,19 @@
 asym_load["q_specified"] = [[0.5e6, 0.0, 0.0], [0.0, 0.2e6, 0.0]]  # input for three phase per entry
 
 # source
-source = initialize_array("input", "source", 1)
+source = initialize_array(DatasetType.input, ComponentType.source, 1)
 source["id"] = [5]
 source["node"] = [1]
 source["status"] = [1]
 source["u_ref"] = [1.0]
 
 # input_data
-input_data = {"node": node, "line": line, "asym_load": asym_load, "source": source}
+input_data = {
+    ComponentType.node: node,
+    ComponentType.line: line,
+    ComponentType.asym_load: asym_load,
+    ComponentType.source: source,
+}
 
 # call constructor
 model = PowerGridModel(input_data, system_frequency=50.0)
@@ -62,18 +69,18 @@
 result = model.calculate_power_flow(symmetric=False)
 
 print("Node Input")
-print(pd.DataFrame(input_data["node"]))
+print(pd.DataFrame(input_data[ComponentType.node]))
 print("Node Result")
-print(result["node"]["u"])  # N*3 array, in symmetric calculation is this N array
-print(result["asym_load"]["p"])  # N*3 array, in symmetric calculation is this N array
+print(result[ComponentType.node]["u"])  # N*3 array, in symmetric calculation is this N array
+print(result[ComponentType.asym_load]["p"])  # N*3 array, in symmetric calculation is this N array
 
 # batch calculation
 scaler = np.linspace(0, 1, 1000)
 batch_p = asym_load["p_specified"].reshape(1, 2, 3) * scaler.reshape(-1, 1, 1)
-batch_load = initialize_array("update", "asym_load", (1000, 2))
+batch_load = initialize_array(DatasetType.update, ComponentType.asym_load, (1000, 2))
 batch_load["id"] = [[4, 8]]
 batch_load["p_specified"] = batch_p
-batch_update = {"asym_load": batch_load}
+batch_update = {ComponentType.asym_load: batch_load}
 
 result = model.calculate_power_flow(symmetric=False, update_data=batch_update)
-print(result["node"]["u"].shape)  # 1000 (scenarios) *3 (nodes) *3 (phases)
+print(result[ComponentType.node]["u"].shape)  # 1000 (scenarios) *3 (nodes) *3 (phases)
diff --git a/src/power_grid_model/__init__.py b/src/power_grid_model/__init__.py
index f0126da1e..605f0deeb 100644
--- a/src/power_grid_model/__init__.py
+++ b/src/power_grid_model/__init__.py
@@ -4,6 +4,7 @@
 
 """Power Grid Model"""
 
+from power_grid_model.core.dataset_definitions import ComponentType, DatasetType
 from power_grid_model.core.power_grid_meta import initialize_array, power_grid_meta_data
 from power_grid_model.core.power_grid_model import PowerGridModel
 from power_grid_model.enum import (
diff --git a/src/power_grid_model/_utils.py b/src/power_grid_model/_utils.py
index b4c120069..2d4e21607 100644
--- a/src/power_grid_model/_utils.py
+++ b/src/power_grid_model/_utils.py
@@ -10,16 +10,19 @@
 We do not officially support this functionality and may remove features in this library at any given time!
 """
 
-from typing import List, Optional, cast
+from typing import List, Optional, Union, cast
 
 import numpy as np
 
+from power_grid_model.core.dataset_definitions import ComponentType
 from power_grid_model.data_types import (
     BatchArray,
     BatchDataset,
     BatchList,
     Dataset,
+    DenseBatchArray,
     PythonDataset,
+    SingleArray,
     SingleDataset,
     SinglePythonDataset,
     SparseBatchArray,
@@ -95,14 +98,15 @@ def get_and_verify_batch_sizes(batch_data: BatchDataset) -> int:
     """
 
     n_batch_size = 0
-    checked_components: List[str] = []
+    checked_components: List[ComponentType] = []
     for component, data in batch_data.items():
         n_component_batch_size = get_batch_size(data)
         if checked_components and n_component_batch_size != n_batch_size:
             if len(checked_components) == 1:
                 checked_components_str = f"'{checked_components.pop()}'"
             else:
-                checked_components_str = "/".join(sorted(checked_components))
+                str_checked_components = [str(component) for component in checked_components]
+                checked_components_str = "/".join(sorted(str_checked_components))
             raise ValueError(
                 f"Inconsistent number of batches in batch data. "
                 f"Component '{component}' contains {n_component_batch_size} batches, "
@@ -143,7 +147,9 @@ def get_batch_size(batch_data: BatchArray) -> int:
     return n_batches
 
 
-def split_numpy_array_in_batches(data: np.ndarray, component: str) -> List[np.ndarray]:
+def split_numpy_array_in_batches(
+    data: Union[DenseBatchArray, SingleArray], component: ComponentType
+) -> List[np.ndarray]:
     """
     Split a single dense numpy array into one or more batches
 
@@ -170,7 +176,7 @@ def split_numpy_array_in_batches(data: np.ndarray, component: str) -> List[np.nd
     )
 
 
-def split_sparse_batches_in_batches(batch_data: SparseBatchArray, component: str) -> List[np.ndarray]:
+def split_sparse_batches_in_batches(batch_data: SparseBatchArray, component: ComponentType) -> List[np.ndarray]:
     """
     Split a single numpy array representing, a compressed sparse structure, into one or more batches
 
diff --git a/src/power_grid_model/core/buffer_handling.py b/src/power_grid_model/core/buffer_handling.py
index 4d4e690cf..82e69581f 100644
--- a/src/power_grid_model/core/buffer_handling.py
+++ b/src/power_grid_model/core/buffer_handling.py
@@ -12,6 +12,7 @@
 
 import numpy as np
 
+from power_grid_model.core.dataset_definitions import ComponentType
 from power_grid_model.core.error_handling import VALIDATOR_MSG
 from power_grid_model.core.index_integer import IdxC, IdxNp
 from power_grid_model.core.power_grid_core import IdxPtr, VoidPtr
@@ -230,7 +231,9 @@ def get_buffer_view(data: Union[np.ndarray, Mapping[str, np.ndarray]], schema: C
     return _get_sparse_buffer_view(data, schema)
 
 
-def create_buffer(properties: BufferProperties, schema: ComponentMetaData) -> Union[np.ndarray, Dict[str, np.ndarray]]:
+def create_buffer(
+    properties: BufferProperties, schema: ComponentMetaData
+) -> Union[np.ndarray, Dict[ComponentType, np.ndarray]]:
     """
     Create a buffer with the provided properties and type.
 
diff --git a/src/power_grid_model/core/data_handling.py b/src/power_grid_model/core/data_handling.py
index 833ee36b1..0dcf33b3b 100644
--- a/src/power_grid_model/core/data_handling.py
+++ b/src/power_grid_model/core/data_handling.py
@@ -12,6 +12,7 @@
 
 import numpy as np
 
+from power_grid_model.core.dataset_definitions import ComponentType, DatasetType
 from power_grid_model.core.power_grid_dataset import CConstDataset, CMutableDataset
 from power_grid_model.core.power_grid_meta import initialize_array, power_grid_meta_data
 from power_grid_model.enum import CalculationType
@@ -20,13 +21,14 @@
 class OutputType(Enum):
     """
     The different supported output types:
-        - sym_output
-        - asym_output
+        - DatasetType.sym_output
+        - DatasetType.asym_output
+        - DatasetType.sc_output
     """
 
-    SYM_OUTPUT = "sym_output"
-    ASYM_OUTPUT = "asym_output"
-    SC_OUTPUT = "sc_output"
+    SYM_OUTPUT = DatasetType.sym_output
+    ASYM_OUTPUT = DatasetType.asym_output
+    SC_OUTPUT = DatasetType.sc_output
 
 
 def get_output_type(*, calculation_type: CalculationType, symmetric: bool) -> OutputType:
@@ -52,7 +54,7 @@ def get_output_type(*, calculation_type: CalculationType, symmetric: bool) -> Ou
     raise NotImplementedError()
 
 
-def prepare_input_view(input_data: Mapping[str, np.ndarray]) -> CConstDataset:
+def prepare_input_view(input_data: Mapping[ComponentType, np.ndarray]) -> CConstDataset:
     """
     Create a view of the input data in a format compatible with the PGM core libary.
 
@@ -63,10 +65,12 @@ def prepare_input_view(input_data: Mapping[str, np.ndarray]) -> CConstDataset:
     Returns:
         instance of CConstDataset ready to be fed into C API
     """
-    return CConstDataset(input_data, dataset_type="input")
+    return CConstDataset(input_data, dataset_type=DatasetType.input)
 
 
-def prepare_update_view(update_data: Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]]) -> CConstDataset:
+def prepare_update_view(
+    update_data: Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]]
+) -> CConstDataset:
     """
     Create a view of the update data, or an empty view if not provided, in a format compatible with the PGM core libary.
 
@@ -77,10 +81,10 @@ def prepare_update_view(update_data: Mapping[str, Union[np.ndarray, Mapping[str,
     Returns:
         instance of CConstDataset ready to be fed into C API
     """
-    return CConstDataset(update_data, dataset_type="update")
+    return CConstDataset(update_data, dataset_type=DatasetType.update)
 
 
-def prepare_output_view(output_data: Mapping[str, np.ndarray], output_type: OutputType) -> CMutableDataset:
+def prepare_output_view(output_data: Mapping[ComponentType, np.ndarray], output_type: OutputType) -> CMutableDataset:
     """
     create a view of the output data in a format compatible with the PGM core libary.
 
@@ -97,12 +101,12 @@ def prepare_output_view(output_data: Mapping[str, np.ndarray], output_type: Outp
 
 
 def create_output_data(
-    output_component_types: Union[Set[str], List[str]],
+    output_component_types: Union[Set[ComponentType], List[ComponentType]],
     output_type: OutputType,
-    all_component_count: Dict[str, int],
+    all_component_count: Dict[ComponentType, int],
     is_batch: bool,
     batch_size: int,
-) -> Dict[str, np.ndarray]:
+) -> Dict[ComponentType, np.ndarray]:
     """
     Create the output data that the user can use. always returns batch type output data.
         Use reduce_output_data to flatten to single scenario output if applicable.
diff --git a/src/power_grid_model/core/dataset_definitions.py b/src/power_grid_model/core/dataset_definitions.py
new file mode 100644
index 000000000..d8f0c2a93
--- /dev/null
+++ b/src/power_grid_model/core/dataset_definitions.py
@@ -0,0 +1,103 @@
+# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
+#
+# SPDX-License-Identifier: MPL-2.0
+
+"""Data types for power grid model dataset and component types."""
+
+# This file is automatically generated. DO NOT modify it manually!
+
+from enum import Enum, EnumMeta
+from typing import Any, Dict, Mapping
+
+# pylint: disable=invalid-name
+
+# fmt: off
+
+class _MetaEnum(EnumMeta):
+    def __contains__(cls, member):
+        """
+        Check if member is part of the Enum.
+
+        Args:
+            member: Member to check.
+
+        Returns:
+            bool: True if the member is part of the Enum, False otherwise.
+        """
+        return member in cls.__members__.keys()
+
+
+class DatasetType(str, Enum, metaclass=_MetaEnum):
+    """
+    A DatasetType is the type of a :class:`Dataset` in power grid model.
+
+    - Examples:
+
+        - DatasetType.input = "input"
+        - DatasetType.update = "update"
+    """
+
+    input = "input"
+    sym_output = "sym_output"
+    asym_output = "asym_output"
+    update = "update"
+    sc_output = "sc_output"
+
+
+class ComponentType(str, Enum):
+    """
+    A ComponentType is the type of a grid component.
+
+    - Examples:
+
+        - ComponentType.node = "node"
+        - ComponentType.line = "line"
+    """
+
+    node = "node"
+    line = "line"
+    link = "link"
+    transformer = "transformer"
+    transformer_tap_regulator = "transformer_tap_regulator"
+    three_winding_transformer = "three_winding_transformer"
+    sym_load = "sym_load"
+    sym_gen = "sym_gen"
+    asym_load = "asym_load"
+    asym_gen = "asym_gen"
+    shunt = "shunt"
+    source = "source"
+    sym_voltage_sensor = "sym_voltage_sensor"
+    asym_voltage_sensor = "asym_voltage_sensor"
+    sym_power_sensor = "sym_power_sensor"
+    asym_power_sensor = "asym_power_sensor"
+    fault = "fault"
+
+
+# pylint: enable=invalid-name
+
+
+def _str_to_datatype(data_type: Any) -> DatasetType:
+    """Helper function to transform data_type str to DatasetType."""
+    if isinstance(data_type, str):
+        return DatasetType[data_type]
+    return data_type
+
+
+def _map_to_datatypes(data: Mapping[Any, Any]) -> Dict[DatasetType, Any]:
+    """Helper function to map datatype str keys to DatasetType."""
+    return {_str_to_datatype(key): value for key, value in data.items()}
+
+
+def _str_to_component_type(component: Any) -> ComponentType:
+    """Helper function to transform component str to ComponentType."""
+    if isinstance(component, str):
+        return ComponentType[component]
+    return component
+
+
+def _map_to_component_types(data: Mapping[Any, Any]) -> Dict[ComponentType, Any]:
+    """Helper function to map componenttype str keys to ComponentType."""
+    return {_str_to_component_type(key): value for key, value in data.items()}
+
+
+# fmt: on
diff --git a/src/power_grid_model/core/power_grid_dataset.py b/src/power_grid_model/core/power_grid_dataset.py
index edd413604..0f48501f5 100644
--- a/src/power_grid_model/core/power_grid_dataset.py
+++ b/src/power_grid_model/core/power_grid_dataset.py
@@ -6,7 +6,7 @@
 Power grid model raw dataset handler
 """
 
-from typing import Dict, List, Mapping, Optional, Union
+from typing import Any, List, Mapping, Optional, Union
 
 import numpy as np
 
@@ -17,6 +17,7 @@
     get_buffer_properties,
     get_buffer_view,
 )
+from power_grid_model.core.dataset_definitions import ComponentType, DatasetType, _str_to_component_type
 from power_grid_model.core.error_handling import VALIDATOR_MSG, assert_no_error
 from power_grid_model.core.power_grid_core import (
     ConstDatasetPtr,
@@ -26,6 +27,7 @@
     power_grid_core as pgc,
 )
 from power_grid_model.core.power_grid_meta import DatasetMetaData, power_grid_meta_data
+from power_grid_model.data_types import Dataset
 from power_grid_model.errors import PowerGridError
 
 
@@ -82,16 +84,19 @@ def n_components(self) -> int:
         """
         return pgc.dataset_info_n_components(self._info)
 
-    def components(self) -> List[str]:
+    def components(self) -> List[ComponentType]:
         """
         The components in the dataset.
 
         Returns:
             A list of the component names in the dataset
         """
-        return [pgc.dataset_info_component_name(self._info, idx) for idx in range(self.n_components())]
+        return [
+            _str_to_component_type(pgc.dataset_info_component_name(self._info, idx))
+            for idx in range(self.n_components())
+        ]
 
-    def elements_per_scenario(self) -> Mapping[str, int]:
+    def elements_per_scenario(self) -> Mapping[ComponentType, int]:
         """
         The number of elements per scenario in the dataset.
 
@@ -104,7 +109,7 @@ def elements_per_scenario(self) -> Mapping[str, int]:
             for idx, component_name in enumerate(self.components())
         }
 
-    def total_elements(self) -> Mapping[str, int]:
+    def total_elements(self) -> Mapping[ComponentType, int]:
         """
         The total number of elements in the dataset.
 
@@ -119,7 +124,7 @@ def total_elements(self) -> Mapping[str, int]:
         }
 
 
-def get_dataset_type(data: Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]]) -> str:
+def get_dataset_type(data: Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]]) -> DatasetType:
     """
     Deduce the dataset type from the provided dataset.
 
@@ -174,7 +179,7 @@ class CMutableDataset:
     The dataset will create mutable buffers that the Power Grid Model can use to load data.
     """
 
-    _dataset_type: str
+    _dataset_type: DatasetType
     _schema: DatasetMetaData
     _is_batch: bool
     _batch_size: int
@@ -183,14 +188,17 @@ class CMutableDataset:
 
     def __new__(
         cls,
-        data: Union[Mapping[str, np.ndarray], Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]]],
-        dataset_type: Optional[str] = None,
+        data: Union[
+            Mapping[ComponentType, np.ndarray],
+            Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]],
+        ],
+        dataset_type: Any = None,
     ):
         instance = super().__new__(cls)
         instance._mutable_dataset = MutableDatasetPtr()
         instance._buffer_views = []
 
-        instance._dataset_type = dataset_type if isinstance(dataset_type, str) else get_dataset_type(data)
+        instance._dataset_type = dataset_type if dataset_type in DatasetType else get_dataset_type(data)
         instance._schema = power_grid_meta_data[instance._dataset_type]
 
         if data:
@@ -202,7 +210,7 @@ def __new__(
             instance._batch_size = 1
 
         instance._mutable_dataset = pgc.create_dataset_mutable(
-            instance._dataset_type, instance._is_batch, instance._batch_size
+            instance._dataset_type.value, instance._is_batch, instance._batch_size
         )
         assert_no_error()
 
@@ -239,7 +247,11 @@ def get_buffer_views(self) -> List[CBuffer]:
         return self._buffer_views
 
     def _add_data(
-        self, data: Union[Mapping[str, np.ndarray], Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]]]
+        self,
+        data: Union[
+            Mapping[ComponentType, np.ndarray],
+            Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]],
+        ],
     ):
         """
         Add Power Grid Model data to the mutable dataset view.
@@ -256,7 +268,10 @@ def _add_data(
             self._add_component_data(component, component_data, allow_unknown=False)
 
     def _add_component_data(
-        self, component: str, data: Union[np.ndarray, Mapping[str, np.ndarray]], allow_unknown: bool = False
+        self,
+        component: ComponentType,
+        data: Union[np.ndarray, Mapping[str, np.ndarray]],
+        allow_unknown: bool = False,
     ):
         """
         Add Power Grid Model data for a single component to the mutable dataset view.
@@ -281,10 +296,10 @@ def _add_component_data(
         self._buffer_views.append(c_buffer)
         self._register_buffer(component, c_buffer)
 
-    def _register_buffer(self, component, buffer: CBuffer):
+    def _register_buffer(self, component: ComponentType, buffer: CBuffer):
         pgc.dataset_mutable_add_buffer(
             dataset=self._mutable_dataset,
-            component=component,
+            component=component.value,
             elements_per_scenario=buffer.n_elements_per_scenario,
             total_elements=buffer.total_elements,
             indptr=buffer.indptr,
@@ -321,8 +336,11 @@ class CConstDataset:
 
     def __new__(
         cls,
-        data: Union[Mapping[str, np.ndarray], Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]]],
-        dataset_type: Optional[str] = None,
+        data: Union[
+            Mapping[ComponentType, np.ndarray],
+            Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]],
+        ],
+        dataset_type: Optional[DatasetType] = None,
     ):
         instance = super().__new__(cls)
         instance._const_dataset = ConstDatasetPtr()
@@ -375,7 +393,7 @@ def __init__(self, dataset_ptr: WritableDatasetPtr):
         self._schema = power_grid_meta_data[self._dataset_type]
 
         self._component_buffer_properties = self._get_buffer_properties(info)
-        self._data: Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]] = {}
+        self._data: Dataset = {}
         self._buffers: Mapping[str, CBuffer] = {}
 
         self._add_buffers()
@@ -399,7 +417,7 @@ def get_info(self) -> CDatasetInfo:
         """
         return CDatasetInfo(pgc.dataset_writable_get_info(self._writable_dataset))
 
-    def get_data(self) -> Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]:
+    def get_data(self) -> Dataset:
         """
         Retrieve data from the Power Grid Model dataset.
 
@@ -410,7 +428,7 @@ def get_data(self) -> Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]:
         """
         return self._data
 
-    def get_component_data(self, component: str) -> Union[np.ndarray, Mapping[str, np.ndarray]]:
+    def get_component_data(self, component: ComponentType) -> Union[np.ndarray, Mapping[str, np.ndarray]]:
         """
         Retrieve Power Grid Model data from the dataset for a specific component.
 
@@ -426,20 +444,20 @@ def _add_buffers(self):
         for component, buffer_properties in self._component_buffer_properties.items():
             self._add_buffer(component, buffer_properties)
 
-    def _add_buffer(self, component: str, buffer_properties: BufferProperties):
+    def _add_buffer(self, component: ComponentType, buffer_properties: BufferProperties):
         schema = self._schema[component]
 
         self._data[component] = create_buffer(buffer_properties, schema)
         self._register_buffer(component, get_buffer_view(self._data[component], schema))
 
-    def _register_buffer(self, component: str, buffer: CBuffer):
+    def _register_buffer(self, component: ComponentType, buffer: CBuffer):
         pgc.dataset_writable_set_buffer(
             dataset=self._writable_dataset, component=component, indptr=buffer.indptr, data=buffer.data
         )
         assert_no_error()
 
     @staticmethod
-    def _get_buffer_properties(info: CDatasetInfo) -> Mapping[str, BufferProperties]:
+    def _get_buffer_properties(info: CDatasetInfo) -> Mapping[ComponentType, BufferProperties]:
         is_batch = info.is_batch()
         batch_size = info.batch_size()
         components = info.components()
diff --git a/src/power_grid_model/core/power_grid_meta.py b/src/power_grid_model/core/power_grid_meta.py
index 75012388d..dec9ccc28 100644
--- a/src/power_grid_model/core/power_grid_meta.py
+++ b/src/power_grid_model/core/power_grid_meta.py
@@ -12,6 +12,12 @@
 
 import numpy as np
 
+from power_grid_model.core.dataset_definitions import (
+    ComponentType,
+    DatasetType,
+    _str_to_component_type,
+    _str_to_datatype,
+)
 from power_grid_model.core.power_grid_core import AttributePtr, ComponentPtr, DatasetPtr, power_grid_core as pgc
 
 
@@ -60,8 +66,8 @@ def __getitem__(self, item):
         return getattr(self, item)
 
 
-DatasetMetaData = Dict[str, ComponentMetaData]
-PowerGridMetaData = Dict[str, DatasetMetaData]
+DatasetMetaData = Dict[ComponentType, ComponentMetaData]
+PowerGridMetaData = Dict[DatasetType, DatasetMetaData]
 
 
 def _generate_meta_data() -> PowerGridMetaData:
@@ -74,7 +80,7 @@ def _generate_meta_data() -> PowerGridMetaData:
     n_datasets = pgc.meta_n_datasets()
     for i in range(n_datasets):
         dataset = pgc.meta_get_dataset_by_idx(i)
-        py_meta_data[pgc.meta_dataset_name(dataset)] = _generate_meta_dataset(dataset)
+        py_meta_data[_str_to_datatype(pgc.meta_dataset_name(dataset))] = _generate_meta_dataset(dataset)
     return py_meta_data
 
 
@@ -91,7 +97,9 @@ def _generate_meta_dataset(dataset: DatasetPtr) -> DatasetMetaData:
     n_components = pgc.meta_n_components(dataset)
     for i in range(n_components):
         component = pgc.meta_get_component_by_idx(dataset, i)
-        py_meta_dataset[pgc.meta_component_name(component)] = _generate_meta_component(component)
+        py_meta_dataset[_str_to_component_type(pgc.meta_component_name(component))] = _generate_meta_component(
+            component
+        )
     return py_meta_dataset
 
 
@@ -156,7 +164,12 @@ def _generate_meta_attributes(component: ComponentPtr) -> dict:
 power_grid_meta_data = _generate_meta_data()
 
 
-def initialize_array(data_type: str, component_type: str, shape: Union[tuple, int], empty: bool = False) -> np.ndarray:
+def initialize_array(
+    data_type: Union[str, DatasetType],
+    component_type: Union[str, ComponentType],
+    shape: Union[tuple, int],
+    empty: bool = False,
+) -> np.ndarray:
     """
     Initializes an array for use in Power Grid Model calculations
 
@@ -171,6 +184,8 @@ def initialize_array(data_type: str, component_type: str, shape: Union[tuple, in
     Returns:
         np structured array with all entries as null value
     """
+    data_type = _str_to_datatype(data_type)
+    component_type = _str_to_component_type(component_type)
     if not isinstance(shape, tuple):
         shape = (shape,)
     if empty:
diff --git a/src/power_grid_model/core/power_grid_model.py b/src/power_grid_model/core/power_grid_model.py
index e7c1ecda2..fd41c5e54 100644
--- a/src/power_grid_model/core/power_grid_model.py
+++ b/src/power_grid_model/core/power_grid_model.py
@@ -17,10 +17,12 @@
     prepare_output_view,
     prepare_update_view,
 )
+from power_grid_model.core.dataset_definitions import ComponentType, _map_to_component_types, _str_to_component_type
 from power_grid_model.core.error_handling import PowerGridBatchError, assert_no_error, handle_errors
 from power_grid_model.core.index_integer import IdNp, IdxNp
 from power_grid_model.core.options import Options
 from power_grid_model.core.power_grid_core import ConstDatasetPtr, IDPtr, IdxPtr, ModelPtr, power_grid_core as pgc
+from power_grid_model.data_types import Dataset
 from power_grid_model.enum import (
     CalculationMethod,
     CalculationType,
@@ -36,7 +38,7 @@ class PowerGridModel:
     """
 
     _model_ptr: ModelPtr
-    _all_component_count: Optional[Dict[str, int]]
+    _all_component_count: Optional[Dict[ComponentType, int]]
     _batch_error: Optional[PowerGridBatchError]
 
     @property
@@ -56,7 +58,7 @@ def _model(self):
         return self._model_ptr
 
     @property
-    def all_component_count(self) -> Dict[str, int]:
+    def all_component_count(self) -> Dict[ComponentType, int]:
         """
         Get count of number of elements per component type.
         If the count for a component type is zero, it will not be in the returned dictionary.
@@ -93,7 +95,9 @@ def __new__(cls, *_args, **_kwargs):
         instance._all_component_count = None
         return instance
 
-    def __init__(self, input_data: Dict[str, np.ndarray], system_frequency: float = 50.0):
+    def __init__(
+        self, input_data: Union[Dict[ComponentType, np.ndarray], Dict[str, np.ndarray]], system_frequency: float = 50.0
+    ):
         """
         Initialize the model from an input data set.
 
@@ -109,12 +113,13 @@ def __init__(self, input_data: Dict[str, np.ndarray], system_frequency: float =
         pgc.destroy_model(self._model_ptr)
         self._all_component_count = None
         # create new
+        input_data = _map_to_component_types(input_data)
         prepared_input = prepare_input_view(input_data)
         self._model_ptr = pgc.create_model(system_frequency, input_data=prepared_input.get_dataset_ptr())
         assert_no_error()
         self._all_component_count = {k: v for k, v in prepared_input.get_info().total_elements().items() if v > 0}
 
-    def update(self, *, update_data: Dict[str, np.ndarray]):
+    def update(self, *, update_data: Union[Dict[ComponentType, np.ndarray], Dict[str, np.ndarray]]):
         """
         Update the model with changes.
 
@@ -127,11 +132,12 @@ def update(self, *, update_data: Dict[str, np.ndarray]):
         Returns:
             None
         """
+        update_data = _map_to_component_types(update_data)
         prepared_update = prepare_update_view(update_data)
         pgc.update_model(self._model, prepared_update.get_dataset_ptr())
         assert_no_error()
 
-    def get_indexer(self, component_type: str, ids: np.ndarray):
+    def get_indexer(self, component_type: Union[ComponentType, str], ids: np.ndarray):
         """
         Get array of indexers given array of ids for component type
 
@@ -142,6 +148,7 @@ def get_indexer(self, component_type: str, ids: np.ndarray):
         Returns:
             Array of indexers, same shape as input array ids
         """
+        component_type = _str_to_component_type(component_type)
         ids_c = np.ascontiguousarray(ids, dtype=IdNp).ctypes.data_as(IDPtr)
         indexer = np.empty_like(ids, dtype=IdxNp, order="C")
         indexer_c = indexer.ctypes.data_as(IdxPtr)
@@ -153,14 +160,25 @@ def get_indexer(self, component_type: str, ids: np.ndarray):
 
     def _get_output_component_count(self, calculation_type: CalculationType):
         exclude_types = {
-            CalculationType.power_flow: ["sensor", "fault"],
-            CalculationType.state_estimation: ["fault"],
-            CalculationType.short_circuit: ["sensor"],
+            CalculationType.power_flow: [
+                ComponentType.sym_voltage_sensor,
+                ComponentType.asym_voltage_sensor,
+                ComponentType.sym_power_sensor,
+                ComponentType.asym_power_sensor,
+                ComponentType.fault,
+            ],
+            CalculationType.state_estimation: [ComponentType.fault],
+            CalculationType.short_circuit: [
+                ComponentType.sym_voltage_sensor,
+                ComponentType.asym_voltage_sensor,
+                ComponentType.sym_power_sensor,
+                ComponentType.asym_power_sensor,
+            ],
         }.get(calculation_type, [])
 
-        def include_type(component_type: str):
+        def include_type(component_type: ComponentType):
             for exclude_type in exclude_types:
-                if exclude_type in component_type:
+                if exclude_type.value in component_type.value:
                     return False
             return True
 
@@ -169,12 +187,12 @@ def include_type(component_type: str):
     # pylint: disable=too-many-arguments
     def _construct_output(
         self,
-        output_component_types: Optional[Union[Set[str], List[str]]],
+        output_component_types: Optional[Union[Set[ComponentType], List[ComponentType]]],
         calculation_type: CalculationType,
         symmetric: bool,
         is_batch: bool,
         batch_size: int,
-    ) -> Dict[str, np.ndarray]:
+    ) -> Dict[ComponentType, np.ndarray]:
         all_component_count = self._get_output_component_count(calculation_type=calculation_type)
 
         # limit all component count to user specified component types in output
@@ -217,8 +235,8 @@ def _calculate_impl(
         self,
         calculation_type: CalculationType,
         symmetric: bool,
-        update_data: Optional[Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]],
-        output_component_types: Optional[Union[Set[str], List[str]]],
+        update_data: Optional[Dataset],
+        output_component_types: Optional[Union[Set[ComponentType], List[ComponentType]]],
         options: Options,
         continue_on_batch_error: bool,
         decode_error: bool,
@@ -282,9 +300,9 @@ def _calculate_power_flow(
         error_tolerance: float = 1e-8,
         max_iterations: int = 20,
         calculation_method: Union[CalculationMethod, str] = CalculationMethod.newton_raphson,
-        update_data: Optional[Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]] = None,
+        update_data: Optional[Dataset] = None,
         threading: int = -1,
-        output_component_types: Optional[Union[Set[str], List[str]]] = None,
+        output_component_types: Optional[Union[Set[ComponentType], List[ComponentType]]] = None,
         continue_on_batch_error: bool = False,
         decode_error: bool = True,
         tap_changing_strategy: Union[TapChangingStrategy, str] = TapChangingStrategy.disabled,
@@ -318,13 +336,13 @@ def _calculate_state_estimation(
         error_tolerance: float = 1e-8,
         max_iterations: int = 20,
         calculation_method: Union[CalculationMethod, str] = CalculationMethod.iterative_linear,
-        update_data: Optional[Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]] = None,
+        update_data: Optional[Dataset] = None,
         threading: int = -1,
-        output_component_types: Optional[Union[Set[str], List[str]]] = None,
+        output_component_types: Optional[Union[Set[ComponentType], List[ComponentType]]] = None,
         continue_on_batch_error: bool = False,
         decode_error: bool = True,
         experimental_features: Union[_ExperimentalFeatures, str] = _ExperimentalFeatures.disabled,
-    ) -> Dict[str, np.ndarray]:
+    ) -> Dict[ComponentType, np.ndarray]:
         calculation_type = CalculationType.state_estimation
         options = self._options(
             calculation_type=calculation_type,
@@ -349,14 +367,14 @@ def _calculate_short_circuit(
         self,
         *,
         calculation_method: Union[CalculationMethod, str] = CalculationMethod.iec60909,
-        update_data: Optional[Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]] = None,
+        update_data: Optional[Dataset] = None,
         threading: int = -1,
-        output_component_types: Optional[Union[Set[str], List[str]]] = None,
+        output_component_types: Optional[Union[Set[ComponentType], List[ComponentType]]] = None,
         continue_on_batch_error: bool = False,
         decode_error: bool = True,
         short_circuit_voltage_scaling: Union[ShortCircuitVoltageScaling, str] = ShortCircuitVoltageScaling.maximum,
         experimental_features: Union[_ExperimentalFeatures, str] = _ExperimentalFeatures.disabled,
-    ) -> Dict[str, np.ndarray]:
+    ) -> Dict[ComponentType, np.ndarray]:
         calculation_type = CalculationType.short_circuit
         symmetric = False
 
@@ -385,13 +403,18 @@ def calculate_power_flow(
         error_tolerance: float = 1e-8,
         max_iterations: int = 20,
         calculation_method: Union[CalculationMethod, str] = CalculationMethod.newton_raphson,
-        update_data: Optional[Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]] = None,
+        update_data: Optional[
+            Union[
+                Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]],
+                Dataset,
+            ]
+        ] = None,
         threading: int = -1,
-        output_component_types: Optional[Union[Set[str], List[str]]] = None,
+        output_component_types: Optional[Union[Set[ComponentType], List[ComponentType]]] = None,
         continue_on_batch_error: bool = False,
         decode_error: bool = True,
         tap_changing_strategy: Union[TapChangingStrategy, str] = TapChangingStrategy.disabled,
-    ) -> Dict[str, np.ndarray]:
+    ) -> Dict[ComponentType, np.ndarray]:
         """
         Calculate power flow once with the current model attributes.
         Or calculate in batch with the given update dataset in batch.
@@ -459,7 +482,7 @@ def calculate_power_flow(
             error_tolerance=error_tolerance,
             max_iterations=max_iterations,
             calculation_method=calculation_method,
-            update_data=update_data,
+            update_data=(_map_to_component_types(update_data) if update_data is not None else None),
             threading=threading,
             output_component_types=output_component_types,
             continue_on_batch_error=continue_on_batch_error,
@@ -474,12 +497,17 @@ def calculate_state_estimation(
         error_tolerance: float = 1e-8,
         max_iterations: int = 20,
         calculation_method: Union[CalculationMethod, str] = CalculationMethod.iterative_linear,
-        update_data: Optional[Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]] = None,
+        update_data: Optional[
+            Union[
+                Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]],
+                Dataset,
+            ]
+        ] = None,
         threading: int = -1,
-        output_component_types: Optional[Union[Set[str], List[str]]] = None,
+        output_component_types: Optional[Union[Set[ComponentType], List[ComponentType]]] = None,
         continue_on_batch_error: bool = False,
         decode_error: bool = True,
-    ) -> Dict[str, np.ndarray]:
+    ) -> Dict[ComponentType, np.ndarray]:
         """
         Calculate state estimation once with the current model attributes.
         Or calculate in batch with the given update dataset in batch.
@@ -544,7 +572,7 @@ def calculate_state_estimation(
             error_tolerance=error_tolerance,
             max_iterations=max_iterations,
             calculation_method=calculation_method,
-            update_data=update_data,
+            update_data=(_map_to_component_types(update_data) if update_data is not None else None),
             threading=threading,
             output_component_types=output_component_types,
             continue_on_batch_error=continue_on_batch_error,
@@ -555,13 +583,18 @@ def calculate_short_circuit(
         self,
         *,
         calculation_method: Union[CalculationMethod, str] = CalculationMethod.iec60909,
-        update_data: Optional[Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]] = None,
+        update_data: Optional[
+            Union[
+                Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]],
+                Dataset,
+            ]
+        ] = None,
         threading: int = -1,
-        output_component_types: Optional[Union[Set[str], List[str]]] = None,
+        output_component_types: Optional[Union[Set[ComponentType], List[ComponentType]]] = None,
         continue_on_batch_error: bool = False,
         decode_error: bool = True,
         short_circuit_voltage_scaling: Union[ShortCircuitVoltageScaling, str] = ShortCircuitVoltageScaling.maximum,
-    ) -> Dict[str, np.ndarray]:
+    ) -> Dict[ComponentType, np.ndarray]:
         """
         Calculate a short circuit once with the current model attributes.
         Or calculate in batch with the given update dataset in batch
@@ -618,7 +651,7 @@ def calculate_short_circuit(
         """
         return self._calculate_short_circuit(
             calculation_method=calculation_method,
-            update_data=update_data,
+            update_data=(_map_to_component_types(update_data) if update_data is not None else None),
             threading=threading,
             output_component_types=output_component_types,
             continue_on_batch_error=continue_on_batch_error,
diff --git a/src/power_grid_model/core/serialization.py b/src/power_grid_model/core/serialization.py
index 3efb7a1d8..553834966 100644
--- a/src/power_grid_model/core/serialization.py
+++ b/src/power_grid_model/core/serialization.py
@@ -9,10 +9,16 @@
 from abc import ABC, abstractmethod
 from ctypes import byref
 from enum import IntEnum
-from typing import Dict, Mapping, Optional, Union
+from typing import Mapping, Optional, Union
 
 import numpy as np
 
+from power_grid_model.core.dataset_definitions import (
+    ComponentType,
+    DatasetType,
+    _map_to_component_types,
+    _str_to_datatype,
+)
 from power_grid_model.core.error_handling import assert_no_error
 from power_grid_model.core.index_integer import IdxC
 from power_grid_model.core.power_grid_core import (
@@ -23,6 +29,7 @@
     power_grid_core as pgc,
 )
 from power_grid_model.core.power_grid_dataset import CConstDataset, CWritableDataset
+from power_grid_model.data_types import Dataset
 from power_grid_model.errors import PowerGridSerializationError
 
 
@@ -63,7 +70,7 @@ def __del__(self):
         if hasattr(self, "_deserializer"):
             pgc.destroy_deserializer(self._deserializer)
 
-    def load(self) -> Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]:
+    def load(self) -> Dataset:
         """
         Load the deserialized data to a new dataset.
 
@@ -83,15 +90,21 @@ class Serializer(ABC):
     Serializer for the Power grid model
     """
 
-    _data: Union[Mapping[str, np.ndarray], Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]]]
+    _data: Union[
+        Mapping[ComponentType, np.ndarray],
+        Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]],
+    ]
     _dataset: CConstDataset
     _serializer: SerializerPtr
 
     def __new__(
         cls,
-        data: Union[Mapping[str, np.ndarray], Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]]],
+        data: Union[
+            Mapping[ComponentType, np.ndarray],
+            Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]],
+        ],
         serialization_type: SerializationType,
-        dataset_type: Optional[str] = None,
+        dataset_type: Optional[DatasetType] = None,
     ):
         instance = super().__new__(cls)
 
@@ -197,8 +210,11 @@ class JsonSerializer(_StringSerializer):  # pylint: disable=too-few-public-metho
 
     def __new__(
         cls,
-        data: Union[Mapping[str, np.ndarray], Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]]],
-        dataset_type: Optional[str] = None,
+        data: Union[
+            Mapping[ComponentType, np.ndarray],
+            Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]],
+        ],
+        dataset_type: Optional[DatasetType] = None,
     ):
         return super().__new__(cls, data, SerializationType.JSON, dataset_type=dataset_type)
 
@@ -210,13 +226,16 @@ class MsgpackSerializer(_BytesSerializer):  # pylint: disable=too-few-public-met
 
     def __new__(
         cls,
-        data: Union[Mapping[str, np.ndarray], Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]]],
-        dataset_type: Optional[str] = None,
+        data: Union[
+            Mapping[ComponentType, np.ndarray],
+            Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]],
+        ],
+        dataset_type: Optional[DatasetType] = None,
     ):
         return super().__new__(cls, data, SerializationType.MSGPACK, dataset_type=dataset_type)
 
 
-def json_deserialize(data: Union[str, bytes]) -> Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]:
+def json_deserialize(data: Union[str, bytes]) -> Dataset:
     """
     Load serialized JSON data to a new dataset.
 
@@ -236,8 +255,11 @@ def json_deserialize(data: Union[str, bytes]) -> Dict[str, Union[np.ndarray, Dic
 
 
 def json_serialize(
-    data: Union[Mapping[str, np.ndarray], Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]]],
-    dataset_type: Optional[str] = None,
+    data: Union[
+        Mapping[ComponentType, np.ndarray],
+        Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]],
+    ],
+    dataset_type: Optional[DatasetType] = None,
     use_compact_list: bool = False,
     indent: int = 2,
 ) -> str:
@@ -261,12 +283,14 @@ def json_serialize(
     Returns:
         A serialized string containing the dataset.
     """
+    data = _map_to_component_types(data)
+    dataset_type = _str_to_datatype(dataset_type)
     result = JsonSerializer(data=data, dataset_type=dataset_type).dump(use_compact_list=use_compact_list, indent=indent)
     assert_no_error()
     return result
 
 
-def msgpack_deserialize(data: bytes) -> Dict[str, Union[np.ndarray, Dict[str, np.ndarray]]]:
+def msgpack_deserialize(data: bytes) -> Dataset:
     """
     Load serialized msgpack data to a new dataset.
 
@@ -286,8 +310,11 @@ def msgpack_deserialize(data: bytes) -> Dict[str, Union[np.ndarray, Dict[str, np
 
 
 def msgpack_serialize(
-    data: Union[Mapping[str, np.ndarray], Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]]],
-    dataset_type: Optional[str] = None,
+    data: Union[
+        Mapping[ComponentType, np.ndarray],
+        Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]],
+    ],
+    dataset_type: Optional[DatasetType] = None,
     use_compact_list: bool = False,
 ) -> bytes:
     """
@@ -308,6 +335,8 @@ def msgpack_serialize(
     Returns:
         A serialized string containing the dataset.
     """
+    data = _map_to_component_types(data)
+    dataset_type = _str_to_datatype(dataset_type)
     result = MsgpackSerializer(data=data, dataset_type=dataset_type).dump(use_compact_list=use_compact_list)
     assert_no_error()
     return result
diff --git a/src/power_grid_model/data_types.py b/src/power_grid_model/data_types.py
index 875cfb0e3..4ad7f43f4 100644
--- a/src/power_grid_model/data_types.py
+++ b/src/power_grid_model/data_types.py
@@ -11,6 +11,8 @@
 
 import numpy as np
 
+from power_grid_model.core.dataset_definitions import ComponentType
+
 # When we're dropping python 3.8, we should introduce proper NumPy type hinting
 
 SingleArray = Union[np.ndarray]
@@ -60,7 +62,7 @@
 A data array can be a :class:`SingleArray` or a :class:`BatchArray`.
 """
 
-SingleDataset = Dict[str, SingleArray]
+SingleDataset = Dict[ComponentType, SingleArray]
 """
 A single dataset is a dictionary where the keys are the component types and the values are
 :class:`SingleArray`
@@ -68,7 +70,7 @@
 - Example: {"node": :class:`SingleArray`, "line": :class:`SingleArray`}
 """
 
-BatchDataset = Dict[str, BatchArray]
+BatchDataset = Dict[ComponentType, BatchArray]
 """
 A batch dataset is a dictionary where the keys are the component types and the values are :class:`BatchArray`
 
@@ -142,7 +144,7 @@
 - Example: [{"id": 1, "u_rated": 10500.0}, {"id": 2, "u_rated": 10500.0}]
 """
 
-SinglePythonDataset = Dict[str, ComponentList]
+SinglePythonDataset = Dict[ComponentType, ComponentList]
 """
 A single dataset in native python representation is a dictionary, where the keys are the component names and the
 values are a list of all the instances of such a component. In essence it stores the same information as a
diff --git a/src/power_grid_model/utils.py b/src/power_grid_model/utils.py
index a54d7815e..267009ada 100644
--- a/src/power_grid_model/utils.py
+++ b/src/power_grid_model/utils.py
@@ -17,6 +17,7 @@
     get_and_verify_batch_sizes as _get_and_verify_batch_sizes,
     get_batch_size as _get_batch_size,
 )
+from power_grid_model.core.dataset_definitions import DatasetType, _map_to_component_types
 from power_grid_model.core.power_grid_dataset import get_dataset_type
 from power_grid_model.core.serialization import (  # pylint: disable=unused-import
     json_deserialize,
@@ -107,7 +108,7 @@ def json_deserialize_from_file(file_path: Path) -> Dataset:
 def json_serialize_to_file(
     file_path: Path,
     data: Dataset,
-    dataset_type: Optional[str] = None,
+    dataset_type: Optional[DatasetType] = None,
     use_compact_list: bool = False,
     indent: Optional[int] = 2,
 ):
@@ -123,6 +124,7 @@ def json_serialize_to_file(
     Returns:
         Save to file.
     """
+    data = _map_to_component_types(data)
     result = json_serialize(
         data=data, dataset_type=dataset_type, use_compact_list=use_compact_list, indent=-1 if indent is None else indent
     )
@@ -150,7 +152,7 @@ def msgpack_deserialize_from_file(file_path: Path) -> Dataset:
 
 
 def msgpack_serialize_to_file(
-    file_path: Path, data: Dataset, dataset_type: Optional[str] = None, use_compact_list: bool = False
+    file_path: Path, data: Dataset, dataset_type: Optional[DatasetType] = None, use_compact_list: bool = False
 ):
     """
     Export msgpack data in most recent format.
@@ -164,6 +166,7 @@ def msgpack_serialize_to_file(
     Returns:
         Save to file.
     """
+    data = _map_to_component_types(data)
     result = msgpack_serialize(data=data, dataset_type=dataset_type, use_compact_list=use_compact_list)
 
     with open(file_path, mode="wb") as file_pointer:
@@ -190,7 +193,7 @@ def import_json_data(json_file: Path, data_type: str, *args, **kwargs) -> Datase
     if kwargs:
         warnings.warn(f"Provided keyword arguments {list(kwargs.keys())} are deprecated.", DeprecationWarning)
 
-    return _compatibility_deprecated_import_json_data(json_file=json_file, data_type=data_type)
+    return _compatibility_deprecated_import_json_data(json_file=json_file, data_type=data_type)  # type: ignore
 
 
 def export_json_data(
@@ -252,7 +255,7 @@ def import_input_data(json_file: Path) -> SingleDataset:
     """
     warnings.warn(_DEPRECATED_JSON_DESERIALIZATION_MSG, DeprecationWarning)
 
-    data = _compatibility_deprecated_import_json_data(json_file=json_file, data_type="input")
+    data = _compatibility_deprecated_import_json_data(json_file=json_file, data_type=DatasetType.input)
     assert isinstance(data, dict)
     assert all(isinstance(component, np.ndarray) and component.ndim == 1 for component in data.values())
     return cast_type(SingleDataset, data)
@@ -274,10 +277,13 @@ def import_update_data(json_file: Path) -> BatchDataset:
     """
     warnings.warn(_DEPRECATED_JSON_DESERIALIZATION_MSG, DeprecationWarning)
 
-    return cast_type(BatchDataset, _compatibility_deprecated_import_json_data(json_file=json_file, data_type="update"))
+    return cast_type(
+        BatchDataset,
+        _compatibility_deprecated_import_json_data(json_file=json_file, data_type=DatasetType.update),
+    )
 
 
-def _compatibility_deprecated_import_json_data(json_file: Path, data_type: str):
+def _compatibility_deprecated_import_json_data(json_file: Path, data_type: DatasetType):
     with open(json_file, mode="r", encoding="utf-8") as file_pointer:
         data = json.load(file_pointer)
 
diff --git a/src/power_grid_model/validation/errors.py b/src/power_grid_model/validation/errors.py
index 64c4a8d2e..cfc2415c6 100644
--- a/src/power_grid_model/validation/errors.py
+++ b/src/power_grid_model/validation/errors.py
@@ -10,6 +10,8 @@
 from enum import Enum
 from typing import Any, Dict, Iterable, List, Optional, Set, Tuple, Type, Union
 
+from power_grid_model import ComponentType
+
 
 class ValidationError(ABC):
     """
@@ -30,18 +32,18 @@ class ValidationError(ABC):
 
     """
 
-    component: Optional[Union[str, List[str]]] = None
+    component: Optional[Union[ComponentType, List[ComponentType]]] = None
     """
     The component, or components, to which the error applies.
     """
 
-    field: Optional[Union[str, List[str], List[Tuple[str, str]]]] = None
+    field: Optional[Union[str, List[str], List[Tuple[ComponentType, str]]]] = None
     """
     The field, or fields, to which the error applies. A field can also be a tuple (component, field) when multiple
     components are being addressed.
     """
 
-    ids: Optional[Union[List[int], List[Tuple[str, int]]]] = None
+    ids: Optional[Union[List[int], List[Tuple[ComponentType, int]]]] = None
     """
     The object identifiers to which the error applies. A field object identifier can also be a tuple (component, id)
     when multiple components are being addressed.
@@ -113,11 +115,11 @@ class SingleFieldValidationError(ValidationError):
     """
 
     _message = "Field {field} is not valid for {n} {objects}."
-    component: str
+    component: ComponentType
     field: str
     ids: List[int]
 
-    def __init__(self, component: str, field: str, ids: Iterable[int]):
+    def __init__(self, component: ComponentType, field: str, ids: Iterable[int]):
         """
         Args:
             component: Component name
@@ -135,11 +137,11 @@ class MultiFieldValidationError(ValidationError):
     """
 
     _message = "Combination of fields {field} is not valid for {n} {objects}."
-    component: str
+    component: ComponentType
     field: List[str]
     ids: List[int]
 
-    def __init__(self, component: str, fields: List[str], ids: List[int]):
+    def __init__(self, component: ComponentType, fields: List[str], ids: List[int]):
         """
         Args:
             component: Component name
@@ -165,18 +167,18 @@ class MultiComponentValidationError(ValidationError):
     E.g. the two fields `id` fields of the `node` and `line` component: [('node', 'id'), ('line', 'id')].
     """
 
-    component: List[str]
-    field: List[Tuple[str, str]]
-    ids: List[Tuple[str, int]]
+    component: List[ComponentType]
+    field: List[Tuple[ComponentType, str]]
+    ids: List[Tuple[ComponentType, int]]
     _message = "Fields {field} are not valid for {n} {objects}."
 
-    def __init__(self, fields: List[Tuple[str, str]], ids: List[Tuple[str, int]]):
+    def __init__(self, fields: List[Tuple[ComponentType, str]], ids: List[Tuple[ComponentType, int]]):
         """
         Args:
             fields: List of field names, formatted as tuples (component, field)
             ids: List of component IDs (not row indices), formatted as tuples (component, id)
         """
-        self.component = sorted(set(component for component, _ in fields))
+        self.component = sorted(set(component for component, _ in fields), key=str)
         self.field = sorted(fields)
         self.ids = sorted(ids)
 
@@ -187,7 +189,8 @@ def __init__(self, fields: List[Tuple[str, str]], ids: List[Tuple[str, int]]):
 
     @property
     def component_str(self) -> str:
-        return "/".join(self.component)
+        str_components = [str(component) for component in self.component]
+        return "/".join(str_components)
 
     @property
     def field_str(self) -> str:
@@ -205,7 +208,7 @@ class NotIdenticalError(SingleFieldValidationError):
     unique: Set[Any]
     num_unique: int
 
-    def __init__(self, component: str, field: str, ids: Iterable[int], values: List[Any]):
+    def __init__(self, component: ComponentType, field: str, ids: Iterable[int], values: List[Any]):
         super().__init__(component, field, ids)
         self.values = values
         self.unique = set(self.values)
@@ -239,7 +242,7 @@ class InvalidEnumValueError(SingleFieldValidationError):
     _message = "Field {field} contains invalid {enum} values for {n} {objects}."
     enum: Union[Type[Enum], List[Type[Enum]]]
 
-    def __init__(self, component: str, field: str, ids: List[int], enum: Union[Type[Enum], List[Type[Enum]]]):
+    def __init__(self, component: ComponentType, field: str, ids: List[int], enum: Union[Type[Enum], List[Type[Enum]]]):
         super().__init__(component, field, ids)
         self.enum = enum
 
@@ -292,7 +295,7 @@ class IdNotInDatasetError(SingleFieldValidationError):
     _message = "ID does not exist in {ref_dataset} for {n} {objects}."
     ref_dataset: str
 
-    def __init__(self, component: str, ids: List[int], ref_dataset: str):
+    def __init__(self, component: ComponentType, ids: List[int], ref_dataset: str):
         super().__init__(component=component, field="id", ids=ids)
         self.ref_dataset = ref_dataset
 
@@ -317,19 +320,19 @@ class InvalidIdError(SingleFieldValidationError):
     """
 
     _message = "Field {field} does not contain a valid {ref_components} id for {n} {objects}. {filters}"
-    ref_components: List[str]
+    ref_components: List[ComponentType]
 
     def __init__(
         self,
-        component: str,
+        component: ComponentType,
         field: str,
         ids: List[int],
-        ref_components: Union[str, List[str]],
+        ref_components: Union[ComponentType, List[ComponentType]],
         filters: Optional[Dict[str, Any]] = None,
     ):
         # pylint: disable=too-many-arguments
         super().__init__(component=component, field=field, ids=ids)
-        self.ref_components = [ref_components] if isinstance(ref_components, str) else ref_components
+        self.ref_components = [ref_components] if isinstance(ref_components, (str, ComponentType)) else ref_components
         self.filters = filters if filters else None
 
     @property
@@ -372,7 +375,7 @@ class ComparisonError(SingleFieldValidationError):
 
     RefType = Union[int, float, str, Tuple[Union[int, float, str], ...]]
 
-    def __init__(self, component: str, field: str, ids: List[int], ref_value: "ComparisonError.RefType"):
+    def __init__(self, component: ComponentType, field: str, ids: List[int], ref_value: "ComparisonError.RefType"):
         super().__init__(component, field, ids)
         self.ref_value = ref_value
 
@@ -480,7 +483,7 @@ class InvalidAssociatedEnumValueError(MultiFieldValidationError):
 
     def __init__(
         self,
-        component: str,
+        component: ComponentType,
         fields: List[str],
         ids: List[int],
         enum: Union[Type[Enum], List[Type[Enum]]],
diff --git a/src/power_grid_model/validation/rules.py b/src/power_grid_model/validation/rules.py
index c15507a8c..721b43b8b 100644
--- a/src/power_grid_model/validation/rules.py
+++ b/src/power_grid_model/validation/rules.py
@@ -23,7 +23,7 @@
     data: SingleDataset
         The entire input/update data set
 
-    component: str
+    component: ComponentType
         The name of the component, which should be an existing key in the data
 
     field: str
@@ -39,6 +39,7 @@
 
 import numpy as np
 
+from power_grid_model import ComponentType
 from power_grid_model.data_types import SingleDataset
 from power_grid_model.enum import FaultPhase, FaultType, WindingType
 from power_grid_model.validation.errors import (
@@ -80,14 +81,14 @@
 CompError = TypeVar("CompError", bound=ComparisonError)
 
 
-def all_greater_than_zero(data: SingleDataset, component: str, field: str) -> List[NotGreaterThanError]:
+def all_greater_than_zero(data: SingleDataset, component: ComponentType, field: str) -> List[NotGreaterThanError]:
     """
     Check that for all records of a particular type of component, the values in the 'field' column are greater than
     zero. Returns an empty list on success, or a list containing a single error object on failure.
 
     Args:
         data (SingleDataset): The input/update data set for all components
-        component (str): The component of interest
+        component (ComponentType): The component of interest
         field (str): The field of interest
 
     Returns:
@@ -99,7 +100,7 @@ def all_greater_than_zero(data: SingleDataset, component: str, field: str) -> Li
 
 def all_greater_than_or_equal_to_zero(
     data: SingleDataset,
-    component: str,
+    component: ComponentType,
     field: str,
     default_value: Optional[Union[np.ndarray, int, float]] = None,
 ) -> List[NotGreaterOrEqualError]:
@@ -109,7 +110,7 @@ def all_greater_than_or_equal_to_zero(
 
     Args:
         data (SingleDataset): The input/update data set for all components
-        component (str) The component of interest
+        component (ComponentType) The component of interest
         field (str): The field of interest
         default_value (Optional[Union[np.ndarray, int, float]], optional): Some values are not required, but will
             receive a default value in the C++ core. To do a proper input validation, these default values should be
@@ -124,7 +125,7 @@ def all_greater_than_or_equal_to_zero(
 
 
 def all_greater_than(
-    data: SingleDataset, component: str, field: str, ref_value: Union[int, float, str]
+    data: SingleDataset, component: ComponentType, field: str, ref_value: Union[int, float, str]
 ) -> List[NotGreaterThanError]:
     """
     Check that for all records of a particular type of component, the values in the 'field' column are greater than
@@ -151,7 +152,7 @@ def not_greater(val: np.ndarray, *ref: np.ndarray):
 
 def all_greater_or_equal(
     data: SingleDataset,
-    component: str,
+    component: ComponentType,
     field: str,
     ref_value: Union[int, float, str],
     default_value: Optional[Union[np.ndarray, int, float]] = None,
@@ -187,7 +188,7 @@ def not_greater_or_equal(val: np.ndarray, *ref: np.ndarray):
 
 
 def all_less_than(
-    data: SingleDataset, component: str, field: str, ref_value: Union[int, float, str]
+    data: SingleDataset, component: ComponentType, field: str, ref_value: Union[int, float, str]
 ) -> List[NotLessThanError]:
     """
     Check that for all records of a particular type of component, the values in the 'field' column are less than the
@@ -213,7 +214,7 @@ def not_less(val: np.ndarray, *ref: np.ndarray):
 
 
 def all_less_or_equal(
-    data: SingleDataset, component: str, field: str, ref_value: Union[int, float, str]
+    data: SingleDataset, component: ComponentType, field: str, ref_value: Union[int, float, str]
 ) -> List[NotLessOrEqualError]:
     """
     Check that for all records of a particular type of component, the values in the 'field' column are less than,
@@ -242,7 +243,7 @@ def not_less_or_equal(val: np.ndarray, *ref: np.ndarray):
 
 def all_between(  # pylint: disable=too-many-arguments
     data: SingleDataset,
-    component: str,
+    component: ComponentType,
     field: str,
     ref_value_1: Union[int, float, str],
     ref_value_2: Union[int, float, str],
@@ -282,7 +283,7 @@ def outside(val: np.ndarray, *ref: np.ndarray) -> np.ndarray:
 
 def all_between_or_at(  # pylint: disable=too-many-arguments
     data: SingleDataset,
-    component: str,
+    component: ComponentType,
     field: str,
     ref_value_1: Union[int, float, str],
     ref_value_2: Union[int, float, str],
@@ -332,7 +333,7 @@ def outside(val: np.ndarray, *ref: np.ndarray) -> np.ndarray:
 
 def none_match_comparison(
     data: SingleDataset,
-    component: str,
+    component: ComponentType,
     field: str,
     compare_fn: Callable,
     ref_value: ComparisonError.RefType,
@@ -383,7 +384,7 @@ def none_match_comparison(
     return []
 
 
-def all_identical(data: SingleDataset, component: str, field: str) -> List[NotIdenticalError]:
+def all_identical(data: SingleDataset, component: ComponentType, field: str) -> List[NotIdenticalError]:
     """
     Check that for all records of a particular type of component, the values in the 'field' column are identical.
 
@@ -407,7 +408,7 @@ def all_identical(data: SingleDataset, component: str, field: str) -> List[NotId
 
 
 def all_enabled_identical(
-    data: SingleDataset, component: str, field: str, status_field: str
+    data: SingleDataset, component: ComponentType, field: str, status_field: str
 ) -> List[NotIdenticalError]:
     """
     Check that for all records of a particular type of component, the values in the 'field' column are identical.
@@ -435,7 +436,7 @@ def all_enabled_identical(
     )
 
 
-def all_unique(data: SingleDataset, component: str, field: str) -> List[NotUniqueError]:
+def all_unique(data: SingleDataset, component: ComponentType, field: str) -> List[NotUniqueError]:
     """
     Check that for all records of a particular type of component, the values in the 'field' column are unique within
     the 'field' column of that component.
@@ -459,7 +460,7 @@ def all_unique(data: SingleDataset, component: str, field: str) -> List[NotUniqu
 
 
 def all_cross_unique(
-    data: SingleDataset, fields: List[Tuple[str, str]], cross_only=True
+    data: SingleDataset, fields: List[Tuple[ComponentType, str]], cross_only=True
 ) -> List[MultiComponentNotUniqueError]:
     """
     Check that for all records of a particular type of component, the values in the 'field' column are unique within
@@ -476,7 +477,7 @@ def all_cross_unique(
         A list containing zero or one MultiComponentNotUniqueError, listing all fields and ids where the value was not
         unique between the fields.
     """
-    all_values: Dict[int, List[Tuple[Tuple[str, str], int]]] = {}
+    all_values: Dict[int, List[Tuple[Tuple[ComponentType, str], int]]] = {}
     duplicate_ids = set()
     for component, field in fields:
         for obj_id, value in zip(data[component]["id"], data[component][field]):
@@ -495,7 +496,7 @@ def all_cross_unique(
 
 
 def all_valid_enum_values(
-    data: SingleDataset, component: str, field: str, enum: Union[Type[Enum], List[Type[Enum]]]
+    data: SingleDataset, component: ComponentType, field: str, enum: Union[Type[Enum], List[Type[Enum]]]
 ) -> List[InvalidEnumValueError]:
     """
     Check that for all records of a particular type of component, the values in the 'field' column are valid values for
@@ -503,7 +504,7 @@ def all_valid_enum_values(
 
     Args:
         data (SingleDataset): The input/update data set for all components
-        component (str): The component of interest
+        component (ComponentType): The component of interest
         field (str): The field of interest
         enum (Type[Enum] | List[Type[Enum]]): The enum type to validate against, or a list of such enum types
 
@@ -526,20 +527,20 @@ def all_valid_enum_values(
 
 def all_valid_associated_enum_values(  # pylint: disable=too-many-arguments
     data: SingleDataset,
-    component: str,
+    component: ComponentType,
     field: str,
     ref_object_id_field: str,
-    ref_components: List[str],
+    ref_components: List[ComponentType],
     enum: Union[Type[Enum], List[Type[Enum]]],
     **filters: Any,
 ) -> List[InvalidAssociatedEnumValueError]:
     """
     Args:
         data (SingleDataset): The input/update data set for all components
-        component (str): The component of interest
+        component (ComponentType): The component of interest
         field (str): The field of interest
         ref_object_id_field (str): The field that contains the referenced component ids
-        ref_components (List[str]): The component or components in which we want to look for ids
+        ref_components (List[ComponentType]): The component or components in which we want to look for ids
         enum (Type[Enum] | List[Type[Enum]]): The enum type to validate against, or a list of such enum types
         **filters: One or more filters on the dataset. E.g. regulated_object="transformer".
 
@@ -567,7 +568,11 @@ def all_valid_associated_enum_values(  # pylint: disable=too-many-arguments
 
 
 def all_valid_ids(
-    data: SingleDataset, component: str, field: str, ref_components: Union[str, List[str]], **filters: Any
+    data: SingleDataset,
+    component: ComponentType,
+    field: str,
+    ref_components: Union[ComponentType, List[ComponentType]],
+    **filters: Any,
 ) -> List[InvalidIdError]:
     """
     For a column which should contain object identifiers (ids), check if the id exists in the data, for a specific set
@@ -595,7 +600,7 @@ def all_valid_ids(
     return []
 
 
-def all_boolean(data: SingleDataset, component: str, field: str) -> List[NotBooleanError]:
+def all_boolean(data: SingleDataset, component: ComponentType, field: str) -> List[NotBooleanError]:
     """
     Check that for all records of a particular type of component, the values in the 'field' column are valid boolean
     values, i.e. 0 or 1. Returns an empty list on success, or a list containing a single error object on failure.
@@ -617,7 +622,7 @@ def all_boolean(data: SingleDataset, component: str, field: str) -> List[NotBool
 
 
 def all_not_two_values_zero(
-    data: SingleDataset, component: str, field_1: str, field_2: str
+    data: SingleDataset, component: ComponentType, field_1: str, field_2: str
 ) -> List[TwoValuesZeroError]:
     """
     Check that for all records of a particular type of component, the values in the 'field_1' and 'field_2' column are
@@ -641,7 +646,9 @@ def all_not_two_values_zero(
     return []
 
 
-def all_not_two_values_equal(data: SingleDataset, component: str, field_1: str, field_2: str) -> List[SameValueError]:
+def all_not_two_values_equal(
+    data: SingleDataset, component: ComponentType, field_1: str, field_2: str
+) -> List[SameValueError]:
     """
     Check that for all records of a particular type of component, the values in the 'field_1' and 'field_2' column are
     not both the same value. E.g. from_node and to_node of a line. Returns an empty list on success, or a list
@@ -666,7 +673,7 @@ def all_not_two_values_equal(data: SingleDataset, component: str, field_1: str,
 
 
 def all_ids_exist_in_data_set(
-    data: SingleDataset, ref_data: SingleDataset, component: str, ref_name: str
+    data: SingleDataset, ref_data: SingleDataset, component: ComponentType, ref_name: str
 ) -> List[IdNotInDatasetError]:
     """
     Check that for all records of a particular type of component, the ids exist in the reference data set.
@@ -687,7 +694,7 @@ def all_ids_exist_in_data_set(
     return []
 
 
-def all_finite(data: SingleDataset, exceptions: Optional[Dict[str, List[str]]] = None) -> List[InfinityError]:
+def all_finite(data: SingleDataset, exceptions: Optional[Dict[ComponentType, List[str]]] = None) -> List[InfinityError]:
     """
     Check that for all records in all component, the values in all columns are finite value, i.e. float values other
     than inf, or -inf. Nan values are ignored, as in all other comparison functions. You can use non_missing() to
@@ -720,7 +727,10 @@ def all_finite(data: SingleDataset, exceptions: Optional[Dict[str, List[str]]] =
 
 
 def none_missing(
-    data: SingleDataset, component: str, fields: Union[List[Union[str, List[str]]], str, List[str]], index: int = 0
+    data: SingleDataset,
+    component: ComponentType,
+    fields: Union[List[Union[str, List[str]]], str, List[str]],
+    index: int = 0,
 ) -> List[MissingValueError]:
     """
     Check that for all records of a particular type of component, the values in the 'fields' columns are not NaN.
@@ -755,7 +765,7 @@ def none_missing(
     return errors
 
 
-def valid_p_q_sigma(data: SingleDataset, component: str) -> List[MultiFieldValidationError]:
+def valid_p_q_sigma(data: SingleDataset, component: ComponentType) -> List[MultiFieldValidationError]:
     """
     Check validity of the pair `(p_sigma, q_sigma)` for 'sym_power_sensor' and 'asym_power_sensor'.
 
@@ -788,7 +798,7 @@ def valid_p_q_sigma(data: SingleDataset, component: str) -> List[MultiFieldValid
 
 
 def all_valid_clocks(
-    data: SingleDataset, component: str, clock_field: str, winding_from_field: str, winding_to_field: str
+    data: SingleDataset, component: ComponentType, clock_field: str, winding_from_field: str, winding_to_field: str
 ) -> List[TransformerClockError]:
     """
     Custom validation rule: Odd clock number is only allowed for Dy(n) or Y(N)d configuration.
@@ -826,7 +836,7 @@ def all_valid_clocks(
 
 
 def all_valid_fault_phases(
-    data: SingleDataset, component: str, fault_type_field: str, fault_phase_field: str
+    data: SingleDataset, component: ComponentType, fault_type_field: str, fault_phase_field: str
 ) -> List[FaultPhaseError]:
     """
     Custom validation rule: Only a subset of fault_phases is supported for each fault type.
@@ -881,19 +891,19 @@ def _fault_phase_supported(fault_type: FaultType, fault_phase: FaultPhase):
 
 def all_supported_tap_control_side(  # pylint: disable=too-many-arguments
     data: SingleDataset,
-    component: str,
+    component: ComponentType,
     control_side_field: str,
     regulated_object_field: str,
-    tap_side_fields: List[Tuple[str, str]],
+    tap_side_fields: List[Tuple[ComponentType, str]],
     **filters: Any,
 ) -> List[UnsupportedTransformerRegulationError]:
     """
     Args:
         data (SingleDataset): The input/update data set for all components
-        component (str): The component of interest
+        component (ComponentType): The component of interest
         control_side_field (str): The field of interest
         regulated_object_field (str): The field that contains the regulated component ids
-        tap_side_fields (List[Tuple[str, str]]): The fields of interest per regulated component,
+        tap_side_fields (List[Tuple[ComponentType, str]]): The fields of interest per regulated component,
             formatted as [(component_1, field_1), (component_2, field_2)]
         **filters: One or more filters on the dataset. E.g. regulated_object="transformer".
 
diff --git a/src/power_grid_model/validation/utils.py b/src/power_grid_model/validation/utils.py
index 3087aca75..e8dd226aa 100644
--- a/src/power_grid_model/validation/utils.py
+++ b/src/power_grid_model/validation/utils.py
@@ -11,6 +11,7 @@
 import numpy as np
 
 from power_grid_model import power_grid_meta_data
+from power_grid_model.core.dataset_definitions import ComponentType, DatasetType, _str_to_component_type
 from power_grid_model.data_types import SingleDataset
 from power_grid_model.validation.errors import ValidationError
 
@@ -96,7 +97,7 @@ def update_input_data(input_data: SingleDataset, update_data: SingleDataset):
     return merged_data
 
 
-def update_component_data(component: str, input_data: np.ndarray, update_data: np.ndarray) -> None:
+def update_component_data(component: ComponentType, input_data: np.ndarray, update_data: np.ndarray) -> None:
     """
     Update the data in a numpy array, with another numpy array,
     indexed on the "id" field and only non-NaN values are overwritten.
@@ -104,7 +105,7 @@ def update_component_data(component: str, input_data: np.ndarray, update_data: n
     for field in update_data.dtype.names:
         if field == "id":
             continue
-        nan = nan_type(component, field, "update")
+        nan = nan_type(component, field, DatasetType.update)
         if np.isnan(nan):
             mask = ~np.isnan(update_data[field])
         else:
@@ -161,10 +162,11 @@ def errors_to_string(
     return msg
 
 
-def nan_type(component: str, field: str, data_type="input"):
+def nan_type(component: Union[str, ComponentType], field: str, data_type: DatasetType = DatasetType.input):
     """
     Helper function to retrieve the nan value for a certain field as defined in the power_grid_meta_data.
     """
+    component = _str_to_component_type(component)
     return power_grid_meta_data[data_type][component].nans[field]
 
 
@@ -204,7 +206,9 @@ def get_indexer(source: np.ndarray, target: np.ndarray, default_value: Optional[
     return np.where(source[clipped_indices] == target, permutation_sort[clipped_indices], default_value)
 
 
-def set_default_value(data: SingleDataset, component: str, field: str, default_value: Union[int, float, np.ndarray]):
+def set_default_value(
+    data: SingleDataset, component: ComponentType, field: str, default_value: Union[int, float, np.ndarray]
+):
     """
     This function sets the default value in the data that is to be validated, so the default values are included in the
     validation.
@@ -230,7 +234,7 @@ def set_default_value(data: SingleDataset, component: str, field: str, default_v
         data[component][field][mask] = default_value
 
 
-def get_valid_ids(data: SingleDataset, ref_components: Union[str, List[str]]) -> List[int]:
+def get_valid_ids(data: SingleDataset, ref_components: Union[ComponentType, List[ComponentType]]) -> List[int]:
     """
     This function returns the valid IDs specified by all ref_components
 
@@ -243,7 +247,7 @@ def get_valid_ids(data: SingleDataset, ref_components: Union[str, List[str]]) ->
     """
     # For convenience, ref_component may be a string and we'll convert it to a 'list' containing that string as it's
     # single element.
-    if isinstance(ref_components, str):
+    if isinstance(ref_components, (str, ComponentType)):
         ref_components = [ref_components]
 
     # Create a set of ids by chaining the ids of all ref_components
@@ -260,7 +264,7 @@ def get_valid_ids(data: SingleDataset, ref_components: Union[str, List[str]]) ->
     return list(valid_ids)
 
 
-def get_mask(data: SingleDataset, component: str, field: str, **filters: Any) -> np.ndarray:
+def get_mask(data: SingleDataset, component: ComponentType, field: str, **filters: Any) -> np.ndarray:
     """
     Get a mask based on the specified filters. E.g. measured_terminal_type=MeasuredTerminalType.source.
 
diff --git a/src/power_grid_model/validation/validation.py b/src/power_grid_model/validation/validation.py
index 12cbfee67..3883cfc55 100644
--- a/src/power_grid_model/validation/validation.py
+++ b/src/power_grid_model/validation/validation.py
@@ -15,7 +15,7 @@
 
 import numpy as np
 
-from power_grid_model import power_grid_meta_data
+from power_grid_model import ComponentType, DatasetType, power_grid_meta_data
 from power_grid_model._utils import convert_batch_dataset_to_batch_list
 from power_grid_model.data_types import BatchDataset, Dataset, SingleDataset
 from power_grid_model.enum import (
@@ -85,7 +85,7 @@ def validate_input_data(
     """
     # A deep copy is made of the input data, since default values will be added in the validation process
     input_data_copy = copy.deepcopy(input_data)
-    assert_valid_data_structure(input_data_copy, "input")
+    assert_valid_data_structure(input_data_copy, DatasetType.input)
 
     errors: List[ValidationError] = []
     errors += validate_required_values(input_data_copy, calculation_type, symmetric)
@@ -127,7 +127,7 @@ def validate_batch_data(
     Raises:
         Error: KeyError | TypeError | ValueError: if the data structure is invalid.
     """
-    assert_valid_data_structure(input_data, "input")
+    assert_valid_data_structure(input_data, DatasetType.input)
 
     input_errors: List[ValidationError] = list(validate_unique_ids_across_components(input_data))
 
@@ -136,7 +136,7 @@ def validate_batch_data(
 
     errors = {}
     for batch, batch_update_data in enumerate(batch_data):
-        assert_valid_data_structure(batch_update_data, "update")
+        assert_valid_data_structure(batch_update_data, DatasetType.update)
         id_errors: List[ValidationError] = list(validate_ids_exist(batch_update_data, input_data))
 
         batch_errors = input_errors + id_errors
@@ -151,7 +151,7 @@ def validate_batch_data(
     return errors if errors else None
 
 
-def assert_valid_data_structure(data: Dataset, data_type: str) -> None:
+def assert_valid_data_structure(data: Dataset, data_type: DatasetType) -> None:
     """
     Checks if all component names are valid and if the data inside the component matches the required Numpy
     structured array as defined in the Power Grid Model meta data.
@@ -164,7 +164,7 @@ def assert_valid_data_structure(data: Dataset, data_type: str) -> None:
         Error: KeyError, TypeError
 
     """
-    if data_type not in {"input", "update"}:
+    if data_type not in {DatasetType.input, DatasetType.update}:
         raise KeyError(f"Unexpected data type '{data_type}' (should be 'input' or 'update')")
 
     component_dtype = {component: meta.dtype for component, meta in power_grid_meta_data[data_type].items()}
@@ -204,7 +204,9 @@ def validate_unique_ids_across_components(data: SingleDataset) -> List[MultiComp
     return all_cross_unique(data, [(component, "id") for component in data])
 
 
-def validate_ids_exist(update_data: Dict[str, np.ndarray], input_data: SingleDataset) -> List[IdNotInDatasetError]:
+def validate_ids_exist(
+    update_data: Dict[ComponentType, np.ndarray], input_data: SingleDataset
+) -> List[IdNotInDatasetError]:
     """
     Checks if all ids of the components in the update data exist in the input data. This needs to be true, because you
     can only update existing components.
@@ -225,7 +227,9 @@ def validate_ids_exist(update_data: Dict[str, np.ndarray], input_data: SingleDat
 
 
 def _process_power_sigma_and_p_q_sigma(
-    data: SingleDataset, sensor: str, required_list: Dict[str, List[Union[str, List[str]]]]
+    data: SingleDataset,
+    sensor: ComponentType,
+    required_list: Dict[Union[ComponentType, str], List[Union[str, List[str]]]],
 ) -> None:
     """
     Helper function to process the required list when both `p_sigma` and `q_sigma` exist
@@ -276,7 +280,7 @@ def validate_required_values(
         An empty list if all required data is available, or a list of MissingValueErrors.
     """
     # Base
-    required: Dict[str, List[Union[str, List[str]]]] = {"base": ["id"]}
+    required: Dict[Union[ComponentType, str], List[Union[str, List[str]]]] = {"base": ["id"]}
 
     # Nodes
     required["node"] = required["base"] + ["u_rated"]
@@ -373,7 +377,7 @@ def validate_required_values(
     if calculation_type is None or calculation_type == CalculationType.short_circuit:
         required["fault"] += ["status", "fault_type"]
         if "fault" in data:
-            for elem in data["fault"]["fault_type"]:
+            for elem in data[ComponentType.fault]["fault_type"]:
                 if elem not in (FaultType.three_phase, FaultType.nan):
                     asym_sc = True
                     break
@@ -382,8 +386,8 @@ def validate_required_values(
         required["line"] += ["r0", "x0", "c0", "tan0"]
         required["shunt"] += ["g0", "b0"]
 
-    _process_power_sigma_and_p_q_sigma(data, "sym_power_sensor", required)
-    _process_power_sigma_and_p_q_sigma(data, "asym_power_sensor", required)
+    _process_power_sigma_and_p_q_sigma(data, ComponentType.sym_power_sensor, required)
+    _process_power_sigma_and_p_q_sigma(data, ComponentType.asym_power_sensor, required)
 
     return _validate_required_in_data(data, required)
 
@@ -444,10 +448,10 @@ def validate_values(data: SingleDataset, calculation_type: Optional[CalculationT
         all_finite(
             data,
             {
-                "sym_power_sensor": ["power_sigma"],
-                "asym_power_sensor": ["power_sigma"],
-                "sym_voltage_sensor": ["u_sigma"],
-                "asym_voltage_sensor": ["u_sigma"],
+                ComponentType.sym_power_sensor: ["power_sigma"],
+                ComponentType.asym_power_sensor: ["power_sigma"],
+                ComponentType.sym_voltage_sensor: ["u_sigma"],
+                ComponentType.asym_voltage_sensor: ["u_sigma"],
             },
         )
     )
@@ -455,14 +459,14 @@ def validate_values(data: SingleDataset, calculation_type: Optional[CalculationT
     component_validators = {
         "node": validate_node,
         "line": validate_line,
-        "link": lambda d: validate_branch(d, "link"),
+        "link": lambda d: validate_branch(d, ComponentType.link),
         "transformer": validate_transformer,
         "three_winding_transformer": validate_three_winding_transformer,
         "source": validate_source,
-        "sym_load": lambda d: validate_generic_load_gen(d, "sym_load"),
-        "sym_gen": lambda d: validate_generic_load_gen(d, "sym_gen"),
-        "asym_load": lambda d: validate_generic_load_gen(d, "asym_load"),
-        "asym_gen": lambda d: validate_generic_load_gen(d, "asym_gen"),
+        "sym_load": lambda d: validate_generic_load_gen(d, ComponentType.sym_load),
+        "sym_gen": lambda d: validate_generic_load_gen(d, ComponentType.sym_gen),
+        "asym_load": lambda d: validate_generic_load_gen(d, ComponentType.asym_load),
+        "asym_gen": lambda d: validate_generic_load_gen(d, ComponentType.asym_gen),
         "shunt": validate_shunt,
     }
 
@@ -472,13 +476,13 @@ def validate_values(data: SingleDataset, calculation_type: Optional[CalculationT
 
     if calculation_type in (None, CalculationType.state_estimation):
         if "sym_voltage_sensor" in data:
-            errors += validate_generic_voltage_sensor(data, "sym_voltage_sensor")
+            errors += validate_generic_voltage_sensor(data, ComponentType.sym_voltage_sensor)
         if "asym_voltage_sensor" in data:
-            errors += validate_generic_voltage_sensor(data, "asym_voltage_sensor")
+            errors += validate_generic_voltage_sensor(data, ComponentType.asym_voltage_sensor)
         if "sym_power_sensor" in data:
-            errors += validate_generic_power_sensor(data, "sym_power_sensor")
+            errors += validate_generic_power_sensor(data, ComponentType.sym_power_sensor)
         if "asym_power_sensor" in data:
-            errors += validate_generic_power_sensor(data, "asym_power_sensor")
+            errors += validate_generic_power_sensor(data, ComponentType.asym_power_sensor)
 
     if calculation_type in (None, CalculationType.short_circuit) and "fault" in data:
         errors += validate_fault(data)
@@ -492,21 +496,21 @@ def validate_values(data: SingleDataset, calculation_type: Optional[CalculationT
 # pylint: disable=missing-function-docstring
 
 
-def validate_base(data: SingleDataset, component: str) -> List[ValidationError]:
+def validate_base(data: SingleDataset, component: ComponentType) -> List[ValidationError]:
     errors: List[ValidationError] = list(all_unique(data, component, "id"))
     return errors
 
 
 def validate_node(data: SingleDataset) -> List[ValidationError]:
-    errors = validate_base(data, "node")
-    errors += all_greater_than_zero(data, "node", "u_rated")
+    errors = validate_base(data, ComponentType.node)
+    errors += all_greater_than_zero(data, ComponentType.node, "u_rated")
     return errors
 
 
-def validate_branch(data: SingleDataset, component: str) -> List[ValidationError]:
+def validate_branch(data: SingleDataset, component: ComponentType) -> List[ValidationError]:
     errors = validate_base(data, component)
-    errors += all_valid_ids(data, component, "from_node", "node")
-    errors += all_valid_ids(data, component, "to_node", "node")
+    errors += all_valid_ids(data, component, "from_node", ComponentType.node)
+    errors += all_valid_ids(data, component, "to_node", ComponentType.node)
     errors += all_not_two_values_equal(data, component, "to_node", "from_node")
     errors += all_boolean(data, component, "from_status")
     errors += all_boolean(data, component, "to_status")
@@ -514,46 +518,56 @@ def validate_branch(data: SingleDataset, component: str) -> List[ValidationError
 
 
 def validate_line(data: SingleDataset) -> List[ValidationError]:
-    errors = validate_branch(data, "line")
-    errors += all_not_two_values_zero(data, "line", "r1", "x1")
-    errors += all_not_two_values_zero(data, "line", "r0", "x0")
-    errors += all_greater_than_zero(data, "line", "i_n")
+    errors = validate_branch(data, ComponentType.line)
+    errors += all_not_two_values_zero(data, ComponentType.line, "r1", "x1")
+    errors += all_not_two_values_zero(data, ComponentType.line, "r0", "x0")
+    errors += all_greater_than_zero(data, ComponentType.line, "i_n")
     return errors
 
 
 def validate_transformer(data: SingleDataset) -> List[ValidationError]:
-    errors = validate_branch(data, "transformer")
-    errors += all_greater_than_zero(data, "transformer", "u1")
-    errors += all_greater_than_zero(data, "transformer", "u2")
-    errors += all_greater_than_zero(data, "transformer", "sn")
-    errors += all_greater_or_equal(data, "transformer", "uk", "pk/sn")
-    errors += all_between(data, "transformer", "uk", 0, 1)
-    errors += all_greater_than_or_equal_to_zero(data, "transformer", "pk")
-    errors += all_greater_or_equal(data, "transformer", "i0", "p0/sn")
-    errors += all_less_than(data, "transformer", "i0", 1)
-    errors += all_greater_than_or_equal_to_zero(data, "transformer", "p0")
-    errors += all_valid_enum_values(data, "transformer", "winding_from", WindingType)
-    errors += all_valid_enum_values(data, "transformer", "winding_to", WindingType)
-    errors += all_between_or_at(data, "transformer", "clock", 0, 12)
-    errors += all_valid_clocks(data, "transformer", "clock", "winding_from", "winding_to")
-    errors += all_valid_enum_values(data, "transformer", "tap_side", BranchSide)
-    errors += all_between_or_at(data, "transformer", "tap_pos", "tap_min", "tap_max", data["transformer"]["tap_nom"], 0)
-    errors += all_between_or_at(data, "transformer", "tap_nom", "tap_min", "tap_max", 0)
-    errors += all_greater_than_or_equal_to_zero(data, "transformer", "tap_size")
-    errors += all_greater_or_equal(data, "transformer", "uk_min", "pk_min/sn", data["transformer"]["uk"])
-    errors += all_between(data, "transformer", "uk_min", 0, 1, data["transformer"]["uk"])
-    errors += all_greater_or_equal(data, "transformer", "uk_max", "pk_max/sn", data["transformer"]["uk"])
-    errors += all_between(data, "transformer", "uk_max", 0, 1, data["transformer"]["uk"])
-    errors += all_greater_than_or_equal_to_zero(data, "transformer", "pk_min", data["transformer"]["pk"])
-    errors += all_greater_than_or_equal_to_zero(data, "transformer", "pk_max", data["transformer"]["pk"])
+    errors = validate_branch(data, ComponentType.transformer)
+    errors += all_greater_than_zero(data, ComponentType.transformer, "u1")
+    errors += all_greater_than_zero(data, ComponentType.transformer, "u2")
+    errors += all_greater_than_zero(data, ComponentType.transformer, "sn")
+    errors += all_greater_or_equal(data, ComponentType.transformer, "uk", "pk/sn")
+    errors += all_between(data, ComponentType.transformer, "uk", 0, 1)
+    errors += all_greater_than_or_equal_to_zero(data, ComponentType.transformer, "pk")
+    errors += all_greater_or_equal(data, ComponentType.transformer, "i0", "p0/sn")
+    errors += all_less_than(data, ComponentType.transformer, "i0", 1)
+    errors += all_greater_than_or_equal_to_zero(data, ComponentType.transformer, "p0")
+    errors += all_valid_enum_values(data, ComponentType.transformer, "winding_from", WindingType)
+    errors += all_valid_enum_values(data, ComponentType.transformer, "winding_to", WindingType)
+    errors += all_between_or_at(data, ComponentType.transformer, "clock", 0, 12)
+    errors += all_valid_clocks(data, ComponentType.transformer, "clock", "winding_from", "winding_to")
+    errors += all_valid_enum_values(data, ComponentType.transformer, "tap_side", BranchSide)
+    errors += all_between_or_at(
+        data, ComponentType.transformer, "tap_pos", "tap_min", "tap_max", data[ComponentType.transformer]["tap_nom"], 0
+    )
+    errors += all_between_or_at(data, ComponentType.transformer, "tap_nom", "tap_min", "tap_max", 0)
+    errors += all_greater_than_or_equal_to_zero(data, ComponentType.transformer, "tap_size")
+    errors += all_greater_or_equal(
+        data, ComponentType.transformer, "uk_min", "pk_min/sn", data[ComponentType.transformer]["uk"]
+    )
+    errors += all_between(data, ComponentType.transformer, "uk_min", 0, 1, data[ComponentType.transformer]["uk"])
+    errors += all_greater_or_equal(
+        data, ComponentType.transformer, "uk_max", "pk_max/sn", data[ComponentType.transformer]["uk"]
+    )
+    errors += all_between(data, ComponentType.transformer, "uk_max", 0, 1, data[ComponentType.transformer]["uk"])
+    errors += all_greater_than_or_equal_to_zero(
+        data, ComponentType.transformer, "pk_min", data[ComponentType.transformer]["pk"]
+    )
+    errors += all_greater_than_or_equal_to_zero(
+        data, ComponentType.transformer, "pk_max", data[ComponentType.transformer]["pk"]
+    )
     return errors
 
 
-def validate_branch3(data: SingleDataset, component: str) -> List[ValidationError]:
+def validate_branch3(data: SingleDataset, component: ComponentType) -> List[ValidationError]:
     errors = validate_base(data, component)
-    errors += all_valid_ids(data, component, "node_1", "node")
-    errors += all_valid_ids(data, component, "node_2", "node")
-    errors += all_valid_ids(data, component, "node_3", "node")
+    errors += all_valid_ids(data, component, "node_1", ComponentType.node)
+    errors += all_valid_ids(data, component, "node_2", ComponentType.node)
+    errors += all_valid_ids(data, component, "node_3", ComponentType.node)
     errors += all_not_two_values_equal(data, component, "node_1", "node_2")
     errors += all_not_two_values_equal(data, component, "node_1", "node_3")
     errors += all_not_two_values_equal(data, component, "node_2", "node_3")
@@ -565,158 +579,254 @@ def validate_branch3(data: SingleDataset, component: str) -> List[ValidationErro
 
 # pylint: disable=R0915
 def validate_three_winding_transformer(data: SingleDataset) -> List[ValidationError]:
-    errors = validate_branch3(data, "three_winding_transformer")
-    errors += all_greater_than_zero(data, "three_winding_transformer", "u1")
-    errors += all_greater_than_zero(data, "three_winding_transformer", "u2")
-    errors += all_greater_than_zero(data, "three_winding_transformer", "u3")
-    errors += all_greater_than_zero(data, "three_winding_transformer", "sn_1")
-    errors += all_greater_than_zero(data, "three_winding_transformer", "sn_2")
-    errors += all_greater_than_zero(data, "three_winding_transformer", "sn_3")
-    errors += all_greater_or_equal(data, "three_winding_transformer", "uk_12", "pk_12/sn_1")
-    errors += all_greater_or_equal(data, "three_winding_transformer", "uk_12", "pk_12/sn_2")
-    errors += all_greater_or_equal(data, "three_winding_transformer", "uk_13", "pk_13/sn_1")
-    errors += all_greater_or_equal(data, "three_winding_transformer", "uk_13", "pk_13/sn_3")
-    errors += all_greater_or_equal(data, "three_winding_transformer", "uk_23", "pk_23/sn_2")
-    errors += all_greater_or_equal(data, "three_winding_transformer", "uk_23", "pk_23/sn_3")
-    errors += all_between(data, "three_winding_transformer", "uk_12", 0, 1)
-    errors += all_between(data, "three_winding_transformer", "uk_13", 0, 1)
-    errors += all_between(data, "three_winding_transformer", "uk_23", 0, 1)
-    errors += all_greater_than_or_equal_to_zero(data, "three_winding_transformer", "pk_12")
-    errors += all_greater_than_or_equal_to_zero(data, "three_winding_transformer", "pk_13")
-    errors += all_greater_than_or_equal_to_zero(data, "three_winding_transformer", "pk_23")
-    errors += all_greater_or_equal(data, "three_winding_transformer", "i0", "p0/sn_1")
-    errors += all_less_than(data, "three_winding_transformer", "i0", 1)
-    errors += all_greater_than_or_equal_to_zero(data, "three_winding_transformer", "p0")
-    errors += all_valid_enum_values(data, "three_winding_transformer", "winding_1", WindingType)
-    errors += all_valid_enum_values(data, "three_winding_transformer", "winding_2", WindingType)
-    errors += all_valid_enum_values(data, "three_winding_transformer", "winding_3", WindingType)
-    errors += all_between_or_at(data, "three_winding_transformer", "clock_12", 0, 12)
-    errors += all_between_or_at(data, "three_winding_transformer", "clock_13", 0, 12)
-    errors += all_valid_clocks(data, "three_winding_transformer", "clock_12", "winding_1", "winding_2")
-    errors += all_valid_clocks(data, "three_winding_transformer", "clock_13", "winding_1", "winding_3")
-    errors += all_valid_enum_values(data, "three_winding_transformer", "tap_side", Branch3Side)
+    errors = validate_branch3(data, ComponentType.three_winding_transformer)
+    errors += all_greater_than_zero(data, ComponentType.three_winding_transformer, "u1")
+    errors += all_greater_than_zero(data, ComponentType.three_winding_transformer, "u2")
+    errors += all_greater_than_zero(data, ComponentType.three_winding_transformer, "u3")
+    errors += all_greater_than_zero(data, ComponentType.three_winding_transformer, "sn_1")
+    errors += all_greater_than_zero(data, ComponentType.three_winding_transformer, "sn_2")
+    errors += all_greater_than_zero(data, ComponentType.three_winding_transformer, "sn_3")
+    errors += all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_12", "pk_12/sn_1")
+    errors += all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_12", "pk_12/sn_2")
+    errors += all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_13", "pk_13/sn_1")
+    errors += all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_13", "pk_13/sn_3")
+    errors += all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_23", "pk_23/sn_2")
+    errors += all_greater_or_equal(data, ComponentType.three_winding_transformer, "uk_23", "pk_23/sn_3")
+    errors += all_between(data, ComponentType.three_winding_transformer, "uk_12", 0, 1)
+    errors += all_between(data, ComponentType.three_winding_transformer, "uk_13", 0, 1)
+    errors += all_between(data, ComponentType.three_winding_transformer, "uk_23", 0, 1)
+    errors += all_greater_than_or_equal_to_zero(data, ComponentType.three_winding_transformer, "pk_12")
+    errors += all_greater_than_or_equal_to_zero(data, ComponentType.three_winding_transformer, "pk_13")
+    errors += all_greater_than_or_equal_to_zero(data, ComponentType.three_winding_transformer, "pk_23")
+    errors += all_greater_or_equal(data, ComponentType.three_winding_transformer, "i0", "p0/sn_1")
+    errors += all_less_than(data, ComponentType.three_winding_transformer, "i0", 1)
+    errors += all_greater_than_or_equal_to_zero(data, ComponentType.three_winding_transformer, "p0")
+    errors += all_valid_enum_values(data, ComponentType.three_winding_transformer, "winding_1", WindingType)
+    errors += all_valid_enum_values(data, ComponentType.three_winding_transformer, "winding_2", WindingType)
+    errors += all_valid_enum_values(data, ComponentType.three_winding_transformer, "winding_3", WindingType)
+    errors += all_between_or_at(data, ComponentType.three_winding_transformer, "clock_12", 0, 12)
+    errors += all_between_or_at(data, ComponentType.three_winding_transformer, "clock_13", 0, 12)
+    errors += all_valid_clocks(data, ComponentType.three_winding_transformer, "clock_12", "winding_1", "winding_2")
+    errors += all_valid_clocks(data, ComponentType.three_winding_transformer, "clock_13", "winding_1", "winding_3")
+    errors += all_valid_enum_values(data, ComponentType.three_winding_transformer, "tap_side", Branch3Side)
     errors += all_between_or_at(
         data,
-        "three_winding_transformer",
+        ComponentType.three_winding_transformer,
         "tap_pos",
         "tap_min",
         "tap_max",
-        data["three_winding_transformer"]["tap_nom"],
+        data[ComponentType.three_winding_transformer]["tap_nom"],
         0,
     )
-    errors += all_between_or_at(data, "three_winding_transformer", "tap_nom", "tap_min", "tap_max", 0)
-    errors += all_greater_than_or_equal_to_zero(data, "three_winding_transformer", "tap_size")
+    errors += all_between_or_at(data, ComponentType.three_winding_transformer, "tap_nom", "tap_min", "tap_max", 0)
+    errors += all_greater_than_or_equal_to_zero(data, ComponentType.three_winding_transformer, "tap_size")
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_12_min", "pk_12_min/sn_1", data["three_winding_transformer"]["uk_12"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_12_min",
+        "pk_12_min/sn_1",
+        data[ComponentType.three_winding_transformer]["uk_12"],
     )
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_12_min", "pk_12_min/sn_2", data["three_winding_transformer"]["uk_12"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_12_min",
+        "pk_12_min/sn_2",
+        data[ComponentType.three_winding_transformer]["uk_12"],
     )
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_13_min", "pk_13_min/sn_1", data["three_winding_transformer"]["uk_13"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_13_min",
+        "pk_13_min/sn_1",
+        data[ComponentType.three_winding_transformer]["uk_13"],
     )
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_13_min", "pk_13_min/sn_3", data["three_winding_transformer"]["uk_13"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_13_min",
+        "pk_13_min/sn_3",
+        data[ComponentType.three_winding_transformer]["uk_13"],
     )
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_23_min", "pk_23_min/sn_2", data["three_winding_transformer"]["uk_23"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_23_min",
+        "pk_23_min/sn_2",
+        data[ComponentType.three_winding_transformer]["uk_23"],
     )
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_23_min", "pk_23_min/sn_3", data["three_winding_transformer"]["uk_23"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_23_min",
+        "pk_23_min/sn_3",
+        data[ComponentType.three_winding_transformer]["uk_23"],
     )
     errors += all_between(
-        data, "three_winding_transformer", "uk_12_min", 0, 1, data["three_winding_transformer"]["uk_12"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_12_min",
+        0,
+        1,
+        data[ComponentType.three_winding_transformer]["uk_12"],
     )
     errors += all_between(
-        data, "three_winding_transformer", "uk_13_min", 0, 1, data["three_winding_transformer"]["uk_13"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_13_min",
+        0,
+        1,
+        data[ComponentType.three_winding_transformer]["uk_13"],
     )
     errors += all_between(
-        data, "three_winding_transformer", "uk_23_min", 0, 1, data["three_winding_transformer"]["uk_23"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_23_min",
+        0,
+        1,
+        data[ComponentType.three_winding_transformer]["uk_23"],
     )
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_12_max", "pk_12_max/sn_1", data["three_winding_transformer"]["uk_12"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_12_max",
+        "pk_12_max/sn_1",
+        data[ComponentType.three_winding_transformer]["uk_12"],
     )
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_12_max", "pk_12_max/sn_2", data["three_winding_transformer"]["uk_12"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_12_max",
+        "pk_12_max/sn_2",
+        data[ComponentType.three_winding_transformer]["uk_12"],
     )
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_13_max", "pk_13_max/sn_1", data["three_winding_transformer"]["uk_13"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_13_max",
+        "pk_13_max/sn_1",
+        data[ComponentType.three_winding_transformer]["uk_13"],
     )
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_13_max", "pk_13_max/sn_3", data["three_winding_transformer"]["uk_13"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_13_max",
+        "pk_13_max/sn_3",
+        data[ComponentType.three_winding_transformer]["uk_13"],
     )
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_23_max", "pk_23_max/sn_2", data["three_winding_transformer"]["uk_23"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_23_max",
+        "pk_23_max/sn_2",
+        data[ComponentType.three_winding_transformer]["uk_23"],
     )
     errors += all_greater_or_equal(
-        data, "three_winding_transformer", "uk_23_max", "pk_23_max/sn_3", data["three_winding_transformer"]["uk_23"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_23_max",
+        "pk_23_max/sn_3",
+        data[ComponentType.three_winding_transformer]["uk_23"],
     )
     errors += all_between(
-        data, "three_winding_transformer", "uk_12_max", 0, 1, data["three_winding_transformer"]["uk_12"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_12_max",
+        0,
+        1,
+        data[ComponentType.three_winding_transformer]["uk_12"],
     )
     errors += all_between(
-        data, "three_winding_transformer", "uk_13_max", 0, 1, data["three_winding_transformer"]["uk_13"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_13_max",
+        0,
+        1,
+        data[ComponentType.three_winding_transformer]["uk_13"],
     )
     errors += all_between(
-        data, "three_winding_transformer", "uk_23_max", 0, 1, data["three_winding_transformer"]["uk_23"]
+        data,
+        ComponentType.three_winding_transformer,
+        "uk_23_max",
+        0,
+        1,
+        data[ComponentType.three_winding_transformer]["uk_23"],
     )
     errors += all_greater_than_or_equal_to_zero(
-        data, "three_winding_transformer", "pk_12_min", data["three_winding_transformer"]["pk_12"]
+        data,
+        ComponentType.three_winding_transformer,
+        "pk_12_min",
+        data[ComponentType.three_winding_transformer]["pk_12"],
     )
     errors += all_greater_than_or_equal_to_zero(
-        data, "three_winding_transformer", "pk_13_min", data["three_winding_transformer"]["pk_13"]
+        data,
+        ComponentType.three_winding_transformer,
+        "pk_13_min",
+        data[ComponentType.three_winding_transformer]["pk_13"],
     )
     errors += all_greater_than_or_equal_to_zero(
-        data, "three_winding_transformer", "pk_23_min", data["three_winding_transformer"]["pk_23"]
+        data,
+        ComponentType.three_winding_transformer,
+        "pk_23_min",
+        data[ComponentType.three_winding_transformer]["pk_23"],
     )
     errors += all_greater_than_or_equal_to_zero(
-        data, "three_winding_transformer", "pk_12_max", data["three_winding_transformer"]["pk_12"]
+        data,
+        ComponentType.three_winding_transformer,
+        "pk_12_max",
+        data[ComponentType.three_winding_transformer]["pk_12"],
     )
     errors += all_greater_than_or_equal_to_zero(
-        data, "three_winding_transformer", "pk_13_max", data["three_winding_transformer"]["pk_13"]
+        data,
+        ComponentType.three_winding_transformer,
+        "pk_13_max",
+        data[ComponentType.three_winding_transformer]["pk_13"],
     )
     errors += all_greater_than_or_equal_to_zero(
-        data, "three_winding_transformer", "pk_23_max", data["three_winding_transformer"]["pk_23"]
+        data,
+        ComponentType.three_winding_transformer,
+        "pk_23_max",
+        data[ComponentType.three_winding_transformer]["pk_23"],
     )
     return errors
 
 
-def validate_appliance(data: SingleDataset, component: str) -> List[ValidationError]:
+def validate_appliance(data: SingleDataset, component: ComponentType) -> List[ValidationError]:
     errors = validate_base(data, component)
     errors += all_boolean(data, component, "status")
-    errors += all_valid_ids(data, component, "node", "node")
+    errors += all_valid_ids(data, component, "node", ComponentType.node)
     return errors
 
 
 def validate_source(data: SingleDataset) -> List[ValidationError]:
-    errors = validate_appliance(data, "source")
-    errors += all_greater_than_zero(data, "source", "u_ref")
-    errors += all_greater_than_zero(data, "source", "sk")
-    errors += all_greater_than_or_equal_to_zero(data, "source", "rx_ratio")
-    errors += all_greater_than_zero(data, "source", "z01_ratio")
+    errors = validate_appliance(data, ComponentType.source)
+    errors += all_greater_than_zero(data, ComponentType.source, "u_ref")
+    errors += all_greater_than_zero(data, ComponentType.source, "sk")
+    errors += all_greater_than_or_equal_to_zero(data, ComponentType.source, "rx_ratio")
+    errors += all_greater_than_zero(data, ComponentType.source, "z01_ratio")
     return errors
 
 
-def validate_generic_load_gen(data: SingleDataset, component: str) -> List[ValidationError]:
+def validate_generic_load_gen(data: SingleDataset, component: ComponentType) -> List[ValidationError]:
     errors = validate_appliance(data, component)
     errors += all_valid_enum_values(data, component, "type", LoadGenType)
     return errors
 
 
 def validate_shunt(data: SingleDataset) -> List[ValidationError]:
-    errors = validate_appliance(data, "shunt")
+    errors = validate_appliance(data, ComponentType.shunt)
     return errors
 
 
-def validate_generic_voltage_sensor(data: SingleDataset, component: str) -> List[ValidationError]:
+def validate_generic_voltage_sensor(data: SingleDataset, component: ComponentType) -> List[ValidationError]:
     errors = validate_base(data, component)
     errors += all_greater_than_zero(data, component, "u_sigma")
     errors += all_greater_than_zero(data, component, "u_measured")
-    errors += all_valid_ids(data, component, "measured_object", "node")
+    errors += all_valid_ids(data, component, "measured_object", ComponentType.node)
     return errors
 
 
-def validate_generic_power_sensor(data: SingleDataset, component: str) -> List[ValidationError]:
+def validate_generic_power_sensor(data: SingleDataset, component: ComponentType) -> List[ValidationError]:
     errors = validate_base(data, component)
     errors += all_greater_than_zero(data, component, "power_sigma")
     errors += all_valid_enum_values(data, component, "measured_terminal_type", MeasuredTerminalType)
@@ -725,86 +835,86 @@ def validate_generic_power_sensor(data: SingleDataset, component: str) -> List[V
         component,
         field="measured_object",
         ref_components=[
-            "node",
-            "line",
-            "transformer",
-            "three_winding_transformer",
-            "source",
-            "shunt",
-            "sym_load",
-            "asym_load",
-            "sym_gen",
-            "asym_gen",
+            ComponentType.node,
+            ComponentType.line,
+            ComponentType.transformer,
+            ComponentType.three_winding_transformer,
+            ComponentType.source,
+            ComponentType.shunt,
+            ComponentType.sym_load,
+            ComponentType.asym_load,
+            ComponentType.sym_gen,
+            ComponentType.asym_gen,
         ],
     )
     errors += all_valid_ids(
         data,
         component,
         field="measured_object",
-        ref_components=["line", "transformer"],
+        ref_components=[ComponentType.line, ComponentType.transformer],
         measured_terminal_type=MeasuredTerminalType.branch_from,
     )
     errors += all_valid_ids(
         data,
         component,
         field="measured_object",
-        ref_components=["line", "transformer"],
+        ref_components=[ComponentType.line, ComponentType.transformer],
         measured_terminal_type=MeasuredTerminalType.branch_to,
     )
     errors += all_valid_ids(
         data,
         component,
         field="measured_object",
-        ref_components="source",
+        ref_components=ComponentType.source,
         measured_terminal_type=MeasuredTerminalType.source,
     )
     errors += all_valid_ids(
         data,
         component,
         field="measured_object",
-        ref_components="shunt",
+        ref_components=ComponentType.shunt,
         measured_terminal_type=MeasuredTerminalType.shunt,
     )
     errors += all_valid_ids(
         data,
         component,
         field="measured_object",
-        ref_components=["sym_load", "asym_load"],
+        ref_components=[ComponentType.sym_load, ComponentType.asym_load],
         measured_terminal_type=MeasuredTerminalType.load,
     )
     errors += all_valid_ids(
         data,
         component,
         field="measured_object",
-        ref_components=["sym_gen", "asym_gen"],
+        ref_components=[ComponentType.sym_gen, ComponentType.asym_gen],
         measured_terminal_type=MeasuredTerminalType.generator,
     )
     errors += all_valid_ids(
         data,
         component,
         field="measured_object",
-        ref_components="three_winding_transformer",
+        ref_components=ComponentType.three_winding_transformer,
         measured_terminal_type=MeasuredTerminalType.branch3_1,
     )
     errors += all_valid_ids(
         data,
         component,
         field="measured_object",
-        ref_components="three_winding_transformer",
+        ref_components=ComponentType.three_winding_transformer,
         measured_terminal_type=MeasuredTerminalType.branch3_2,
     )
     errors += all_valid_ids(
         data,
         component,
         field="measured_object",
-        ref_components="three_winding_transformer",
+        ref_components=ComponentType.three_winding_transformer,
         measured_terminal_type=MeasuredTerminalType.branch3_3,
     )
     errors += all_valid_ids(
         data,
         component,
         field="measured_object",
-        ref_components="node",
+        ref_components=ComponentType.node,
         measured_terminal_type=MeasuredTerminalType.node,
     )
     if component in ("sym_power_sensor", "asym_power_sensor"):
@@ -814,53 +924,64 @@ def validate_generic_power_sensor(data: SingleDataset, component: str) -> List[V
 
 
 def validate_fault(data: SingleDataset) -> List[ValidationError]:
-    errors = validate_base(data, "fault")
-    errors += all_boolean(data, "fault", "status")
-    errors += all_valid_enum_values(data, "fault", "fault_type", FaultType)
-    errors += all_valid_enum_values(data, "fault", "fault_phase", FaultPhase)
-    errors += all_valid_fault_phases(data, "fault", "fault_type", "fault_phase")
-    errors += all_valid_ids(data, "fault", field="fault_object", ref_components="node")
-    errors += all_greater_than_or_equal_to_zero(data, "fault", "r_f")
-    errors += all_enabled_identical(data, "fault", "fault_type", "status")
-    errors += all_enabled_identical(data, "fault", "fault_phase", "status")
+    errors = validate_base(data, ComponentType.fault)
+    errors += all_boolean(data, ComponentType.fault, "status")
+    errors += all_valid_enum_values(data, ComponentType.fault, "fault_type", FaultType)
+    errors += all_valid_enum_values(data, ComponentType.fault, "fault_phase", FaultPhase)
+    errors += all_valid_fault_phases(data, ComponentType.fault, "fault_type", "fault_phase")
+    errors += all_valid_ids(data, ComponentType.fault, field="fault_object", ref_components=ComponentType.node)
+    errors += all_greater_than_or_equal_to_zero(data, ComponentType.fault, "r_f")
+    errors += all_enabled_identical(data, ComponentType.fault, "fault_type", "status")
+    errors += all_enabled_identical(data, ComponentType.fault, "fault_phase", "status")
     return errors
 
 
-def validate_regulator(data: SingleDataset, component: str) -> List[ValidationError]:
+def validate_regulator(data: SingleDataset, component: ComponentType) -> List[ValidationError]:
     errors = validate_base(data, component)
     errors += all_valid_ids(
         data,
         component,
         field="regulated_object",
-        ref_components=["transformer", "three_winding_transformer"],
+        ref_components=[ComponentType.transformer, ComponentType.three_winding_transformer],
     )
     return errors
 
 
 def validate_transformer_tap_regulator(data: SingleDataset) -> List[ValidationError]:
-    errors = validate_regulator(data, "transformer_tap_regulator")
-    errors += all_boolean(data, "transformer_tap_regulator", "status")
-    errors += all_valid_enum_values(data, "transformer_tap_regulator", "control_side", [BranchSide, Branch3Side])
+    errors = validate_regulator(data, ComponentType.transformer_tap_regulator)
+    errors += all_boolean(data, ComponentType.transformer_tap_regulator, "status")
+    errors += all_valid_enum_values(
+        data, ComponentType.transformer_tap_regulator, "control_side", [BranchSide, Branch3Side]
+    )
     errors += all_valid_associated_enum_values(
-        data, "transformer_tap_regulator", "control_side", "regulated_object", ["transformer"], [BranchSide]
+        data,
+        ComponentType.transformer_tap_regulator,
+        "control_side",
+        "regulated_object",
+        [ComponentType.transformer],
+        [BranchSide],
     )
     errors += all_valid_associated_enum_values(
         data,
-        "transformer_tap_regulator",
+        ComponentType.transformer_tap_regulator,
         "control_side",
         "regulated_object",
-        ["three_winding_transformer"],
+        [ComponentType.three_winding_transformer],
         [Branch3Side],
     )
-    errors += all_greater_than_or_equal_to_zero(data, "transformer_tap_regulator", "u_set")
-    errors += all_greater_than_zero(data, "transformer_tap_regulator", "u_band")
-    errors += all_greater_than_or_equal_to_zero(data, "transformer_tap_regulator", "line_drop_compensation_r", 0.0)
-    errors += all_greater_than_or_equal_to_zero(data, "transformer_tap_regulator", "line_drop_compensation_x", 0.0)
+    errors += all_greater_than_or_equal_to_zero(data, ComponentType.transformer_tap_regulator, "u_set")
+    errors += all_greater_than_zero(data, ComponentType.transformer_tap_regulator, "u_band")
+    errors += all_greater_than_or_equal_to_zero(
+        data, ComponentType.transformer_tap_regulator, "line_drop_compensation_r", 0.0
+    )
+    errors += all_greater_than_or_equal_to_zero(
+        data, ComponentType.transformer_tap_regulator, "line_drop_compensation_x", 0.0
+    )
     errors += all_supported_tap_control_side(
         data,
-        "transformer_tap_regulator",
+        ComponentType.transformer_tap_regulator,
         "control_side",
         "regulated_object",
-        [("transformer", "tap_side"), ("three_winding_transformer", "tap_side")],
+        [(ComponentType.transformer, "tap_side"), (ComponentType.three_winding_transformer, "tap_side")],
     )
     return errors


Test patch:
diff --git a/tests/unit/test_dataset.py b/tests/unit/test_dataset.py
index 8cea7518d..32cd3889d 100644
--- a/tests/unit/test_dataset.py
+++ b/tests/unit/test_dataset.py
@@ -7,21 +7,22 @@
 import numpy as np
 import pytest
 
+from power_grid_model.core.dataset_definitions import ComponentType, DatasetType
 from power_grid_model.core.power_grid_dataset import CConstDataset, get_dataset_type
 from power_grid_model.core.power_grid_meta import power_grid_meta_data
 from power_grid_model.errors import PowerGridError
 
 
 def input_dataset_types():
-    return ["input"]
+    return [DatasetType.input]
 
 
 def update_dataset_types():
-    return ["update"]
+    return [DatasetType.update]
 
 
 def output_dataset_types():
-    return ["sym_output", "asym_output", "sc_output"]
+    return [DatasetType.sym_output, DatasetType.asym_output, DatasetType.sc_output]
 
 
 def all_dataset_types():
@@ -37,8 +38,8 @@ def test_get_dataset_type(dataset_type):
     assert (
         get_dataset_type(
             data={
-                "node": np.zeros(1, dtype=power_grid_meta_data[dataset_type]["node"]),
-                "sym_load": np.zeros(1, dtype=power_grid_meta_data[dataset_type]["sym_load"]),
+                ComponentType.node: np.zeros(1, dtype=power_grid_meta_data[dataset_type]["node"]),
+                ComponentType.sym_load: np.zeros(1, dtype=power_grid_meta_data[dataset_type]["sym_load"]),
             }
         )
         == dataset_type
@@ -92,7 +93,7 @@ def test_const_dataset__conflicting_data():
 
 
 def test_const_dataset__single_data(dataset_type):
-    components = {"node": 3, "sym_load": 2, "asym_load": 4}
+    components = {ComponentType.node: 3, ComponentType.sym_load: 2, ComponentType.asym_load: 4}
     data = {
         component: np.zeros(shape=count, dtype=power_grid_meta_data[dataset_type][component])
         for component, count in components.items()
@@ -114,7 +115,7 @@ def test_const_dataset__single_data(dataset_type):
 
 @pytest.mark.parametrize("batch_size", (0, 1, 3))
 def test_const_dataset__uniform_batch_data(dataset_type, batch_size):
-    components = {"node": 3, "sym_load": 2, "asym_load": 4}
+    components = {ComponentType.node: 3, ComponentType.sym_load: 2, ComponentType.asym_load: 4}
     data = {
         component: np.zeros(shape=(batch_size, count), dtype=power_grid_meta_data[dataset_type][component])
         for component, count in components.items()
@@ -136,21 +137,21 @@ def test_const_dataset__uniform_batch_data(dataset_type, batch_size):
 
 def test_const_dataset__sparse_batch_data(dataset_type):
     batch_size = 3
-    components = {"node": 3, "sym_load": 2, "asym_load": 4, "link": 4}
+    components = {ComponentType.node: 3, ComponentType.sym_load: 2, ComponentType.asym_load: 4, ComponentType.link: 4}
     data = {
-        "node": {
+        ComponentType.node: {
             "data": np.zeros(shape=3, dtype=power_grid_meta_data[dataset_type]["node"]),
             "indptr": np.array([0, 2, 3, 3]),
         },
-        "sym_load": {
+        ComponentType.sym_load: {
             "data": np.zeros(shape=2, dtype=power_grid_meta_data[dataset_type]["sym_load"]),
             "indptr": np.array([0, 0, 1, 2]),
         },
-        "asym_load": {
+        ComponentType.asym_load: {
             "data": np.zeros(shape=4, dtype=power_grid_meta_data[dataset_type]["asym_load"]),
             "indptr": np.array([0, 2, 3, 4]),
         },
-        "link": np.zeros(shape=(batch_size, 4), dtype=power_grid_meta_data[dataset_type]["link"]),
+        ComponentType.link: np.zeros(shape=(batch_size, 4), dtype=power_grid_meta_data[dataset_type]["link"]),
     }
 
     dataset = CConstDataset(data, dataset_type)
@@ -163,14 +164,24 @@ def test_const_dataset__sparse_batch_data(dataset_type):
     assert info.batch_size() == 3
     assert info.n_components() == len(components)
     assert info.components() == list(components)
-    assert info.elements_per_scenario() == {"node": -1, "sym_load": -1, "asym_load": -1, "link": 4}
-    assert info.total_elements() == {"node": 3, "sym_load": 2, "asym_load": 4, "link": batch_size * 4}
+    assert info.elements_per_scenario() == {
+        ComponentType.node: -1,
+        ComponentType.sym_load: -1,
+        ComponentType.asym_load: -1,
+        ComponentType.link: 4,
+    }
+    assert info.total_elements() == {
+        ComponentType.node: 3,
+        ComponentType.sym_load: 2,
+        ComponentType.asym_load: 4,
+        ComponentType.link: batch_size * 4,
+    }
 
 
 def test_const_dataset__mixed_batch_size(dataset_type):
     data = {
-        "node": np.zeros(shape=(2, 3), dtype=power_grid_meta_data[dataset_type]["node"]),
-        "line": np.zeros(shape=(3, 3), dtype=power_grid_meta_data[dataset_type]["line"]),
+        ComponentType.node: np.zeros(shape=(2, 3), dtype=power_grid_meta_data[dataset_type]["node"]),
+        ComponentType.line: np.zeros(shape=(3, 3), dtype=power_grid_meta_data[dataset_type]["line"]),
     }
     with pytest.raises(ValueError):
         CConstDataset(data, dataset_type)
diff --git a/tests/unit/test_dataset_definitions.py b/tests/unit/test_dataset_definitions.py
new file mode 100644
index 000000000..190889d92
--- /dev/null
+++ b/tests/unit/test_dataset_definitions.py
@@ -0,0 +1,23 @@
+# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
+#
+# SPDX-License-Identifier: MPL-2.0
+
+import pytest
+
+from power_grid_model import ComponentType, DatasetType, power_grid_meta_data
+
+
+def assert_data_type(pgm_meta_data_types, data_type):
+    pgm_types = [pgm_type for pgm_type in pgm_meta_data_types]
+    pgm_types.sort()
+    generated_types = [member.value for member in data_type]
+    generated_types.sort()
+    assert pgm_types == generated_types
+
+
+def test_power_grid_data_types():
+    assert_data_type(power_grid_meta_data, DatasetType)
+
+
+def test_power_grid_components():
+    assert_data_type(power_grid_meta_data[DatasetType.input], ComponentType)
diff --git a/tests/unit/test_internal_utils.py b/tests/unit/test_internal_utils.py
index 385802191..b003f12db 100644
--- a/tests/unit/test_internal_utils.py
+++ b/tests/unit/test_internal_utils.py
@@ -406,7 +406,7 @@ def test_convert_get_and_verify_batch_sizes_inconsistent_batch_sizes_more_than_t
 
 @patch("power_grid_model._utils.get_and_verify_batch_sizes")
 def test_convert_batch_dataset_to_batch_list_missing_key_sparse(_mock: MagicMock):
-    update_data: BatchDataset = {"foo": {"a": np.empty(3), "data": np.empty(3)}}
+    update_data: BatchDataset = {"foo": {"a": np.empty(3), "data": np.empty(3)}}  # type: ignore
     with pytest.raises(
         KeyError,
         match="Missing 'indptr' in sparse batch data for 'foo' "
diff --git a/tests/unit/test_power_grid_model.py b/tests/unit/test_power_grid_model.py
index f929d6be9..6a9227edb 100644
--- a/tests/unit/test_power_grid_model.py
+++ b/tests/unit/test_power_grid_model.py
@@ -3,11 +3,12 @@
 # SPDX-License-Identifier: MPL-2.0
 
 from copy import copy
+from typing import Dict
 
 import numpy as np
 import pytest
 
-from power_grid_model import PowerGridModel, initialize_array
+from power_grid_model import ComponentType, PowerGridModel, initialize_array
 from power_grid_model.errors import InvalidCalculationMethod, IterationDiverge, PowerGridBatchError, PowerGridError
 from power_grid_model.validation import assert_valid_input_data
 
@@ -81,7 +82,7 @@ def test_simple_update(model: PowerGridModel, case_data):
         "sym_load": update_batch["sym_load"][0, :],
     }
     model.update(update_data=update_data)
-    expected_result = {"node": case_data["output_batch"]["node"][0, :]}
+    expected_result = {ComponentType.node: case_data["output_batch"]["node"][0, :]}
     result = model.calculate_power_flow()
     compare_result(result, expected_result, rtol=0.0, atol=1e-8)
 
@@ -152,8 +153,8 @@ def test_batch_calculation_error_continue(model: PowerGridModel, case_data):
     np.allclose(error.succeeded_scenarios, [0])
     assert "The id cannot be found:" in error.error_messages[0]
     # assert value result for scenario 0
-    result = {"node": result["node"][error.succeeded_scenarios, :]}
-    expected_result = {"node": case_data["output_batch"]["node"][error.succeeded_scenarios, :]}
+    result = {ComponentType.node: result[ComponentType.node][error.succeeded_scenarios, :]}
+    expected_result = {ComponentType.node: case_data["output_batch"][ComponentType.node][error.succeeded_scenarios, :]}
     compare_result(result, expected_result, rtol=0.0, atol=1e-8)
     # general error before the batch
     with pytest.raises(PowerGridError, match="The calculation method is invalid for this calculation!"):
diff --git a/tests/unit/test_serialization.py b/tests/unit/test_serialization.py
index 76136a693..15b66cc2b 100644
--- a/tests/unit/test_serialization.py
+++ b/tests/unit/test_serialization.py
@@ -9,6 +9,7 @@
 import numpy as np
 import pytest
 
+from power_grid_model import ComponentType, DatasetType
 from power_grid_model.core.power_grid_dataset import get_dataset_type
 from power_grid_model.utils import json_deserialize, json_serialize, msgpack_deserialize, msgpack_serialize
 
@@ -32,7 +33,7 @@ def from_msgpack(data):
     return msgpack.unpackb(data)
 
 
-def empty_dataset(dataset_type: str = "input"):
+def empty_dataset(dataset_type: DatasetType = DatasetType.input):
     return {"version": "1.0", "type": dataset_type, "is_batch": False, "attributes": {}, "data": {}}
 
 
@@ -266,7 +267,9 @@ def assert_almost_equal(value: np.ndarray, reference: Any):
 
 
 def assert_scenario_correct(
-    deserialized_dataset: Mapping[str, np.ndarray], serialized_dataset: Mapping[str, Any], sparse_components: List[str]
+    deserialized_dataset: Mapping[ComponentType, np.ndarray],
+    serialized_dataset: Mapping[str, Any],
+    sparse_components: List[ComponentType],
 ):
     for key in serialized_dataset["data"]:
         if key not in deserialized_dataset:
@@ -291,7 +294,7 @@ def assert_scenario_correct(
 
 
 def assert_serialization_correct(
-    deserialized_dataset: Mapping[str, Union[np.ndarray, Mapping[str, np.ndarray]]],
+    deserialized_dataset: Mapping[ComponentType, Union[np.ndarray, Mapping[str, np.ndarray]]],
     serialized_dataset: Mapping[str, Any],
 ):
     """Assert the dataset correctly reprensents the input data."""
@@ -366,7 +369,10 @@ def test_msgpack_deserialize_data(serialized_data):
         assert result_type == serialized_data["type"]
 
 
-@pytest.mark.parametrize("dataset_type", ("input", "update", "sym_output", "asym_output", "sc_output"))
+@pytest.mark.parametrize(
+    "dataset_type",
+    (DatasetType.input, DatasetType.update, DatasetType.sym_output, DatasetType.asym_output, DatasetType.sc_output),
+)
 @pytest.mark.parametrize("use_compact_list", (True, False))
 def test_json_serialize_empty_dataset(dataset_type, use_compact_list: bool):
     for indent in (-1, 0, 2, 4):
@@ -381,7 +387,10 @@ def test_json_serialize_empty_dataset(dataset_type, use_compact_list: bool):
             json_serialize({}, use_compact_list=use_compact_list, indent=indent)
 
 
-@pytest.mark.parametrize("dataset_type", ("input", "update", "sym_output", "asym_output", "sc_output"))
+@pytest.mark.parametrize(
+    "dataset_type",
+    (DatasetType.input, DatasetType.update, DatasetType.sym_output, DatasetType.asym_output, DatasetType.sc_output),
+)
 def test_msgpack_serialize_empty_dataset(dataset_type):
     reference = empty_dataset(dataset_type)
     for use_compact_list in (True, False):
diff --git a/tests/unit/utils.py b/tests/unit/utils.py
index 486753393..0eb7d0c29 100644
--- a/tests/unit/utils.py
+++ b/tests/unit/utils.py
@@ -11,6 +11,7 @@
 import numpy as np
 import pytest
 
+from power_grid_model.core.dataset_definitions import DatasetType
 from power_grid_model.core.power_grid_model import PowerGridModel
 from power_grid_model.data_types import Dataset, PythonDataset, SingleDataset
 from power_grid_model.errors import (
@@ -284,7 +285,7 @@ def compare_result(actual: SingleDataset, expected: SingleDataset, rtol: float,
                 )
 
 
-def convert_python_to_numpy(data: PythonDataset, data_type: str) -> Dataset:
+def convert_python_to_numpy(data: PythonDataset, data_type: DatasetType) -> Dataset:
     """
     Convert native python data to internal numpy
 
diff --git a/tests/unit/validation/test_assertions.py b/tests/unit/validation/test_assertions.py
index 57ed5cf6d..17d4d1592 100644
--- a/tests/unit/validation/test_assertions.py
+++ b/tests/unit/validation/test_assertions.py
@@ -28,10 +28,10 @@ def test_validation_exception(errors_to_string_mock: MagicMock):
 def test_assert_valid_input_data(validate_mock: MagicMock):
     validate_mock.return_value = None
     assert_valid_input_data(
-        input_data={"foo": np.array([1])}, calculation_type=CalculationType.state_estimation, symmetric=False
+        input_data={"foo": np.array([1])}, calculation_type=CalculationType.state_estimation, symmetric=False  # type: ignore
     )
     validate_mock.assert_called_once_with(
-        input_data={"foo": np.array([1])}, calculation_type=CalculationType.state_estimation, symmetric=False
+        input_data={"foo": np.array([1])}, calculation_type=CalculationType.state_estimation, symmetric=False  # type: ignore
     )
 
     validate_mock.return_value = [ValidationError()]
@@ -42,15 +42,15 @@ def test_assert_valid_input_data(validate_mock: MagicMock):
 @patch("power_grid_model.validation.assertions.validate_batch_data")
 def test_assert_valid_batch_data(validate_mock: MagicMock):
     validate_mock.return_value = None
-    assert_valid_batch_data(
-        input_data={"foo": np.array([1])},
-        update_data={"bar": np.array([2])},
+    assert_valid_batch_data(  # type: ignore
+        input_data={"foo": np.array([1])},  # type: ignore
+        update_data={"bar": np.array([2])},  # type: ignore
         calculation_type=CalculationType.state_estimation,
         symmetric=False,
     )
-    validate_mock.assert_called_once_with(
-        input_data={"foo": np.array([1])},
-        update_data={"bar": np.array([2])},
+    validate_mock.assert_called_once_with(  # type: ignore
+        input_data={"foo": np.array([1])},  # type: ignore
+        update_data={"bar": np.array([2])},  # type: ignore
         calculation_type=CalculationType.state_estimation,
         symmetric=False,
     )
diff --git a/tests/unit/validation/test_input_validation.py b/tests/unit/validation/test_input_validation.py
index f1e809e9f..7a02be608 100644
--- a/tests/unit/validation/test_input_validation.py
+++ b/tests/unit/validation/test_input_validation.py
@@ -7,7 +7,16 @@
 import numpy as np
 import pytest
 
-from power_grid_model import Branch3Side, BranchSide, LoadGenType, MeasuredTerminalType, WindingType, initialize_array
+from power_grid_model import (
+    Branch3Side,
+    BranchSide,
+    ComponentType,
+    DatasetType,
+    LoadGenType,
+    MeasuredTerminalType,
+    WindingType,
+    initialize_array,
+)
 from power_grid_model.enum import CalculationType, FaultPhase, FaultType
 from power_grid_model.validation import validate_input_data
 from power_grid_model.validation.errors import (
@@ -31,12 +40,12 @@
 
 
 @pytest.fixture
-def input_data() -> Dict[str, np.ndarray]:
-    node = initialize_array("input", "node", 4)
+def input_data() -> Dict[ComponentType, np.ndarray]:
+    node = initialize_array(DatasetType.input, ComponentType.node, 4)
     node["id"] = [0, 2, 1, 2]
     node["u_rated"] = [10.5e3, 10.5e3, 0, 10.5e3]
 
-    line = initialize_array("input", "line", 3)
+    line = initialize_array(DatasetType.input, ComponentType.line, 3)
     line["id"] = [3, 4, 5]
     line["from_node"] = [0, -1, 2]
     line["to_node"] = [2, 1, 8]
@@ -48,14 +57,14 @@ def input_data() -> Dict[str, np.ndarray]:
     line["x0"] = [0, 0, 50]
     line["i_n"] = [-3, 0, 50]
 
-    link = initialize_array("input", "link", 2)
+    link = initialize_array(DatasetType.input, ComponentType.link, 2)
     link["id"] = [12, 13]
     link["from_node"] = [0, -1]
     link["to_node"] = [8, 1]
     link["from_status"] = [3, 1]
     link["to_status"] = [0, 4]
 
-    transformer = initialize_array("input", "transformer", 3)
+    transformer = initialize_array(DatasetType.input, ComponentType.transformer, 3)
     transformer["id"] = [1, 14, 15]
     transformer["from_node"] = [1, 7, 2]  # TODO check from node 1 to node 1
     transformer["to_node"] = [1, 8, 1]
@@ -82,7 +91,7 @@ def input_data() -> Dict[str, np.ndarray]:
     transformer["pk_min"] = [300.0, 0.0, nan_type("transformer", "pk_min")]
     transformer["pk_max"] = [400.0, -0.1, nan_type("transformer", "pk_max")]
 
-    three_winding_transformer = initialize_array("input", "three_winding_transformer", 4)
+    three_winding_transformer = initialize_array(DatasetType.input, ComponentType.three_winding_transformer, 4)
     three_winding_transformer["id"] = [1, 28, 29, 30]
     three_winding_transformer["node_1"] = [0, 1, 9, 2]
     three_winding_transformer["node_2"] = [1, 15, 1, 0]
@@ -158,7 +167,7 @@ def input_data() -> Dict[str, np.ndarray]:
     three_winding_transformer["pk_13_max"] = [-40, nan_type("three_winding_transformer", "pk_12_max"), 40, 50]
     three_winding_transformer["pk_23_max"] = [-120, nan_type("three_winding_transformer", "pk_12_max"), 40, 30]
 
-    transformer_tap_regulator = initialize_array("input", "transformer_tap_regulator", 5)
+    transformer_tap_regulator = initialize_array(DatasetType.input, ComponentType.transformer_tap_regulator, 5)
     transformer_tap_regulator["id"] = [51, 52, 53, 54, 1]
     transformer_tap_regulator["status"] = [0, -1, 2, 1, 5]
     transformer_tap_regulator["regulated_object"] = [14, 15, 28, 14, 2]
@@ -168,7 +177,7 @@ def input_data() -> Dict[str, np.ndarray]:
     transformer_tap_regulator["line_drop_compensation_r"] = [0.0, -1.0, 1.0, 0.0, 2.0]
     transformer_tap_regulator["line_drop_compensation_x"] = [0.0, 4.0, 2.0, 0.0, -4.0]
 
-    source = initialize_array("input", "source", 3)
+    source = initialize_array(DatasetType.input, ComponentType.source, 3)
     source["id"] = [16, 17, 1]
     source["node"] = [10, 1, 2]
     source["status"] = [0, -1, 2]
@@ -177,42 +186,42 @@ def input_data() -> Dict[str, np.ndarray]:
     source["rx_ratio"] = [0.0, -30.0, 300.0]
     source["z01_ratio"] = [-1.0, 0.0, 200.0]
 
-    shunt = initialize_array("input", "shunt", 3)
+    shunt = initialize_array(DatasetType.input, ComponentType.shunt, 3)
     shunt["id"] = [18, 19, 1]
     shunt["node"] = [10, 1, 2]
     shunt["status"] = [0, -1, 2]
 
-    sym_load = initialize_array("input", "sym_load", 3)
+    sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 3)
     sym_load["id"] = [1, 20, 21]
     sym_load["type"] = [1, 0, 5]
     sym_load["node"] = [10, 1, 2]
     sym_load["status"] = [0, -1, 2]
 
-    sym_gen = initialize_array("input", "sym_gen", 3)
+    sym_gen = initialize_array(DatasetType.input, ComponentType.sym_gen, 3)
     sym_gen["id"] = [1, 22, 23]
     sym_gen["type"] = [2, -1, 1]
     sym_gen["node"] = [10, 1, 2]
     sym_gen["status"] = [0, -1, 2]
 
-    asym_load = initialize_array("input", "asym_load", 3)
+    asym_load = initialize_array(DatasetType.input, ComponentType.asym_load, 3)
     asym_load["id"] = [1, 24, 25]
     asym_load["type"] = [5, 0, 2]
     asym_load["node"] = [10, 1, 2]
     asym_load["status"] = [0, -1, 2]
 
-    asym_gen = initialize_array("input", "asym_gen", 3)
+    asym_gen = initialize_array(DatasetType.input, ComponentType.asym_gen, 3)
     asym_gen["id"] = [1, 26, 27]
     asym_gen["type"] = [-1, 5, 2]
     asym_gen["node"] = [10, 1, 2]
     asym_gen["status"] = [0, -1, 2]
 
-    sym_voltage_sensor = initialize_array("input", "sym_voltage_sensor", 4)
+    sym_voltage_sensor = initialize_array(DatasetType.input, ComponentType.sym_voltage_sensor, 4)
     sym_voltage_sensor["id"] = [7, 8, 9, 10]
     sym_voltage_sensor["measured_object"] = [2, 3, 1, 200]
     sym_voltage_sensor["u_measured"] = [0.0, 10.4e3, 10.6e3, -20.0]
     sym_voltage_sensor["u_sigma"] = [1.0, np.nan, 0.0, -1.0]
 
-    asym_voltage_sensor = initialize_array("input", "asym_voltage_sensor", 4)
+    asym_voltage_sensor = initialize_array(DatasetType.input, ComponentType.asym_voltage_sensor, 4)
     asym_voltage_sensor["id"] = [7, 8, 9, 10]
     asym_voltage_sensor["measured_object"] = [2, 3, 1, 200]
     asym_voltage_sensor["u_measured"] = [
@@ -223,19 +232,19 @@ def input_data() -> Dict[str, np.ndarray]:
     ]
     asym_voltage_sensor["u_sigma"] = [1.0, np.nan, 0.0, -1.0]
 
-    sym_power_sensor = initialize_array("input", "sym_power_sensor", 4)
+    sym_power_sensor = initialize_array(DatasetType.input, ComponentType.sym_power_sensor, 4)
     sym_power_sensor["id"] = [7, 8, 9, 10]
     sym_power_sensor["measured_object"] = [12, 3, 13, 200]
     sym_power_sensor["power_sigma"] = [1.0, np.nan, 0.0, -1.0]
     sym_power_sensor["measured_terminal_type"] = [1, 1, 10, 1]
 
-    asym_power_sensor = initialize_array("input", "asym_power_sensor", 4)
+    asym_power_sensor = initialize_array(DatasetType.input, ComponentType.asym_power_sensor, 4)
     asym_power_sensor["id"] = [7, 8, 9, 10]
     asym_power_sensor["measured_object"] = [12, 3, 13, 200]
     asym_power_sensor["power_sigma"] = [1.0, np.nan, 0.0, -1.0]
     asym_power_sensor["measured_terminal_type"] = [1, 1, 10, 1]
 
-    fault = initialize_array("input", "fault", 20)
+    fault = initialize_array(DatasetType.input, ComponentType.fault, 20)
     fault["id"] = [1] + list(range(32, 51))
     fault["status"] = [0, -1, 2] + 17 * [1]
     fault["fault_type"] = 6 * [0] + 4 * [1] + 4 * [2] + 4 * [3] + [nan_type("fault", "fault_type"), 4]
@@ -245,23 +254,23 @@ def input_data() -> Dict[str, np.ndarray]:
     fault["x_f"] = [-1.0, 0.0, 1.0] + 17 * [nan_type("fault", "x_f")]
 
     data = {
-        "node": node,
-        "line": line,
-        "link": link,
-        "transformer": transformer,
-        "three_winding_transformer": three_winding_transformer,
-        "transformer_tap_regulator": transformer_tap_regulator,
-        "source": source,
-        "shunt": shunt,
-        "sym_load": sym_load,
-        "sym_gen": sym_gen,
-        "asym_load": asym_load,
-        "asym_gen": asym_gen,
-        "sym_voltage_sensor": sym_voltage_sensor,
-        "asym_voltage_sensor": asym_voltage_sensor,
-        "sym_power_sensor": sym_power_sensor,
-        "asym_power_sensor": asym_power_sensor,
-        "fault": fault,
+        ComponentType.node: node,
+        ComponentType.line: line,
+        ComponentType.link: link,
+        ComponentType.transformer: transformer,
+        ComponentType.three_winding_transformer: three_winding_transformer,
+        ComponentType.transformer_tap_regulator: transformer_tap_regulator,
+        ComponentType.source: source,
+        ComponentType.shunt: shunt,
+        ComponentType.sym_load: sym_load,
+        ComponentType.sym_gen: sym_gen,
+        ComponentType.asym_load: asym_load,
+        ComponentType.asym_gen: asym_gen,
+        ComponentType.sym_voltage_sensor: sym_voltage_sensor,
+        ComponentType.asym_voltage_sensor: asym_voltage_sensor,
+        ComponentType.sym_power_sensor: sym_power_sensor,
+        ComponentType.asym_power_sensor: asym_power_sensor,
+        ComponentType.fault: fault,
     }
     return data
 
@@ -272,50 +281,50 @@ def test_validate_input_data_sym_calculation(input_data):
     assert (
         MultiComponentNotUniqueError(
             [
-                ("asym_gen", "id"),
-                ("asym_load", "id"),
-                ("asym_power_sensor", "id"),
-                ("asym_voltage_sensor", "id"),
-                ("node", "id"),
-                ("shunt", "id"),
-                ("source", "id"),
-                ("sym_gen", "id"),
-                ("sym_load", "id"),
-                ("sym_power_sensor", "id"),
-                ("sym_voltage_sensor", "id"),
-                ("transformer", "id"),
-                ("three_winding_transformer", "id"),
-                ("fault", "id"),
-                ("transformer_tap_regulator", "id"),
+                (ComponentType.asym_gen, "id"),
+                (ComponentType.asym_load, "id"),
+                (ComponentType.asym_power_sensor, "id"),
+                (ComponentType.asym_voltage_sensor, "id"),
+                (ComponentType.node, "id"),
+                (ComponentType.shunt, "id"),
+                (ComponentType.source, "id"),
+                (ComponentType.sym_gen, "id"),
+                (ComponentType.sym_load, "id"),
+                (ComponentType.sym_power_sensor, "id"),
+                (ComponentType.sym_voltage_sensor, "id"),
+                (ComponentType.transformer, "id"),
+                (ComponentType.three_winding_transformer, "id"),
+                (ComponentType.fault, "id"),
+                (ComponentType.transformer_tap_regulator, "id"),
             ],
             [
-                ("asym_gen", 1),
-                ("asym_load", 1),
-                ("asym_power_sensor", 7),
-                ("asym_power_sensor", 8),
-                ("asym_power_sensor", 9),
-                ("asym_power_sensor", 10),
-                ("asym_voltage_sensor", 7),
-                ("asym_voltage_sensor", 8),
-                ("asym_voltage_sensor", 9),
-                ("asym_voltage_sensor", 10),
-                ("node", 1),
-                ("shunt", 1),
-                ("source", 1),
-                ("sym_gen", 1),
-                ("sym_load", 1),
-                ("sym_power_sensor", 7),
-                ("sym_power_sensor", 8),
-                ("sym_power_sensor", 9),
-                ("sym_power_sensor", 10),
-                ("sym_voltage_sensor", 7),
-                ("sym_voltage_sensor", 8),
-                ("sym_voltage_sensor", 9),
-                ("sym_voltage_sensor", 10),
-                ("transformer", 1),
-                ("three_winding_transformer", 1),
-                ("fault", 1),
-                ("transformer_tap_regulator", 1),
+                (ComponentType.asym_gen, 1),
+                (ComponentType.asym_load, 1),
+                (ComponentType.asym_power_sensor, 7),
+                (ComponentType.asym_power_sensor, 8),
+                (ComponentType.asym_power_sensor, 9),
+                (ComponentType.asym_power_sensor, 10),
+                (ComponentType.asym_voltage_sensor, 7),
+                (ComponentType.asym_voltage_sensor, 8),
+                (ComponentType.asym_voltage_sensor, 9),
+                (ComponentType.asym_voltage_sensor, 10),
+                (ComponentType.node, 1),
+                (ComponentType.shunt, 1),
+                (ComponentType.source, 1),
+                (ComponentType.sym_gen, 1),
+                (ComponentType.sym_load, 1),
+                (ComponentType.sym_power_sensor, 7),
+                (ComponentType.sym_power_sensor, 8),
+                (ComponentType.sym_power_sensor, 9),
+                (ComponentType.sym_power_sensor, 10),
+                (ComponentType.sym_voltage_sensor, 7),
+                (ComponentType.sym_voltage_sensor, 8),
+                (ComponentType.sym_voltage_sensor, 9),
+                (ComponentType.sym_voltage_sensor, 10),
+                (ComponentType.transformer, 1),
+                (ComponentType.three_winding_transformer, 1),
+                (ComponentType.fault, 1),
+                (ComponentType.transformer_tap_regulator, 1),
             ],
         )
         in validation_errors
@@ -600,13 +609,13 @@ def test_validate_input_data_transformer_tap_regulator(input_data):
 
 def test_fault(input_data):
     validation_errors = validate_input_data(input_data, calculation_type=CalculationType.short_circuit)
-    assert InvalidEnumValueError("fault", "fault_type", [50], FaultType) in validation_errors
-    assert InvalidEnumValueError("fault", "fault_phase", [50], FaultPhase) in validation_errors
-    assert FaultPhaseError("fault", ("fault_type", "fault_phase"), [1] + list(range(32, 51)))
-    assert NotGreaterOrEqualError("fault", "r_f", [1], 0) in validation_errors
+    assert InvalidEnumValueError(ComponentType.fault, "fault_type", [50], FaultType) in validation_errors
+    assert InvalidEnumValueError(ComponentType.fault, "fault_phase", [50], FaultPhase) in validation_errors
+    assert FaultPhaseError(ComponentType.fault, ("fault_type", "fault_phase"), [1] + list(range(32, 51)))
+    assert NotGreaterOrEqualError(ComponentType.fault, "r_f", [1], 0) in validation_errors
     assert (
         NotIdenticalError(
-            "fault",
+            ComponentType.fault,
             "fault_type",
             list(range(32, 51)),
             5 * [0] + 4 * [1] + 4 * [2] + 4 * [3] + [nan_type("fault", "fault_type"), 4],
@@ -615,7 +624,7 @@ def test_fault(input_data):
     )
     assert (
         NotIdenticalError(
-            "fault",
+            ComponentType.fault,
             "fault_phase",
             list(range(32, 51)),
             list(range(2, 7)) + [0, 4, 5, 6] + 2 * list(range(4)) + [nan_type("fault", "fault_phase"), 7],
diff --git a/tests/unit/validation/test_validation_functions.py b/tests/unit/validation/test_validation_functions.py
index 5cdd0f4d6..078dd2b0e 100644
--- a/tests/unit/validation/test_validation_functions.py
+++ b/tests/unit/validation/test_validation_functions.py
@@ -10,6 +10,7 @@
 import pytest
 
 from power_grid_model import CalculationType, LoadGenType, MeasuredTerminalType, initialize_array, power_grid_meta_data
+from power_grid_model.core.dataset_definitions import ComponentType, DatasetType
 from power_grid_model.enum import Branch3Side, BranchSide, CalculationType, FaultType, TapChangingStrategy
 from power_grid_model.validation import assert_valid_input_data
 from power_grid_model.validation.errors import (
@@ -33,7 +34,7 @@
     validate_values,
 )
 
-NaN = power_grid_meta_data["input"]["node"].nans["id"]
+NaN = power_grid_meta_data[DatasetType.input][ComponentType.node].nans["id"]
 
 
 def test_assert_valid_data_structure():
@@ -611,7 +612,7 @@ def test_validate_generic_power_sensor__all_terminal_types(
     all_valid_ids: MagicMock, measured_terminal_type: MeasuredTerminalType
 ):
     # Act
-    validate_generic_power_sensor(data={}, component="")
+    validate_generic_power_sensor(data={}, component="")  # type: ignore
 
     # Assert
     all_valid_ids.assert_any_call(
@@ -642,7 +643,7 @@ def test_validate_generic_power_sensor__terminal_types(
     all_valid_ids: MagicMock, ref_component: Union[str, List[str]], measured_terminal_type: MeasuredTerminalType
 ):
     # Act
-    validate_generic_power_sensor(data={}, component="")
+    validate_generic_power_sensor(data={}, component="")  # type: ignore
 
     # Assert
     all_valid_ids.assert_any_call(