diff --git a/src/safeds/ml/nn/layers/_flatten_layer.py b/src/safeds/ml/nn/layers/_flatten_layer.py
index a84551c2b..35e11c2bb 100644
--- a/src/safeds/ml/nn/layers/_flatten_layer.py
+++ b/src/safeds/ml/nn/layers/_flatten_layer.py
@@ -4,7 +4,7 @@
 from typing import TYPE_CHECKING, Any
 
 from safeds._utils import _structural_hash
-from safeds.ml.nn.typing import ConstantImageSize
+from safeds.ml.nn.typing import ConstantImageSize, TensorShape
 
 from ._layer import Layer
 
@@ -46,14 +46,14 @@ def input_size(self) -> ModelImageSize:
         return self._input_size
 
     @property
-    def output_size(self) -> int:
+    def output_size(self) -> TensorShape:
         """
         Get the output_size of this layer.
 
         Returns
         -------
         result:
-            The number of neurons in this layer.
+            A 1D TensorShape object containing the number of neurons in this layer.
 
         Raises
         ------
@@ -66,9 +66,9 @@ def output_size(self) -> int:
             )
         if self._output_size is None:
             self._output_size = self._input_size.width * self._input_size.height * self._input_size.channel
-        return self._output_size
+        return TensorShape([self._output_size])
 
-    def _set_input_size(self, input_size: int | ModelImageSize) -> None:
+    def _set_input_size(self, input_size: int | TensorShape) -> None:
         if isinstance(input_size, int):
             raise TypeError("The input_size of a flatten layer has to be of type ImageSize.")
         if not isinstance(input_size, ConstantImageSize):
diff --git a/src/safeds/ml/nn/layers/_forward_layer.py b/src/safeds/ml/nn/layers/_forward_layer.py
index e420b78ec..779796fd7 100644
--- a/src/safeds/ml/nn/layers/_forward_layer.py
+++ b/src/safeds/ml/nn/layers/_forward_layer.py
@@ -4,7 +4,7 @@
 
 from safeds._utils import _structural_hash
 from safeds._validation import _check_bounds, _ClosedBound
-from safeds.ml.nn.typing import ModelImageSize
+from safeds.ml.nn.typing import TensorShape
 
 from ._layer import Layer
 
@@ -50,34 +50,34 @@ def _get_internal_layer(self, **kwargs: Any) -> nn.Module:
         return _InternalForwardLayer(self._input_size, self._output_size, activation_function)
 
     @property
-    def input_size(self) -> int:
+    def input_size(self) -> TensorShape:
         """
         Get the input_size of this layer.
 
         Returns
         -------
         result:
-            The amount of values being passed into this layer.
+            A 1D TensorShape object containing the amount of values being passed into this layer.
         """
         if self._input_size is None:
             raise ValueError("The input_size is not yet set.")
 
-        return self._input_size
+        return TensorShape([self._input_size])
 
     @property
-    def output_size(self) -> int:
+    def output_size(self) -> TensorShape:
         """
         Get the output_size of this layer.
 
         Returns
         -------
         result:
-            The number of neurons in this layer.
+            A 1D TensorShape object containing the number of neurons in this layer.
         """
-        return self._output_size
+        return TensorShape([self._output_size])
 
-    def _set_input_size(self, input_size: int | ModelImageSize) -> None:
-        if isinstance(input_size, ModelImageSize):
+    def _set_input_size(self, input_size: int | TensorShape) -> None:
+        if isinstance(input_size, TensorShape):
             raise TypeError("The input_size of a forward layer has to be of type int.")
 
         self._input_size = input_size
diff --git a/src/safeds/ml/nn/layers/_gru_layer.py b/src/safeds/ml/nn/layers/_gru_layer.py
index e74fec417..044200729 100644
--- a/src/safeds/ml/nn/layers/_gru_layer.py
+++ b/src/safeds/ml/nn/layers/_gru_layer.py
@@ -5,7 +5,7 @@
 
 from safeds._utils import _structural_hash
 from safeds._validation import _check_bounds, _ClosedBound
-from safeds.ml.nn.typing import ModelImageSize
+from safeds.ml.nn.typing import TensorShape
 
 from ._layer import Layer
 
@@ -51,33 +51,33 @@ def _get_internal_layer(self, **kwargs: Any) -> nn.Module:
         return _InternalGRULayer(self._input_size, self._output_size, activation_function)
 
     @property
-    def input_size(self) -> int:
+    def input_size(self) -> TensorShape:
         """
         Get the input_size of this layer.
 
         Returns
         -------
         result:
-            The amount of values being passed into this layer.
+            A 1D TensorShape object containing the amount of values being passed into this layer.
         """
         if self._input_size is None:
             raise ValueError("The input_size is not yet set.")
-        return self._input_size
+        return TensorShape([self._input_size])
 
     @property
-    def output_size(self) -> int:
+    def output_size(self) -> TensorShape:
         """
         Get the output_size of this layer.
 
         Returns
         -------
         result:
-            The number of neurons in this layer.
+            A 1D TensorShape object containing the number of neurons in this layer.
         """
-        return self._output_size
+        return TensorShape([self._output_size])
 
-    def _set_input_size(self, input_size: int | ModelImageSize) -> None:
-        if isinstance(input_size, ModelImageSize):
+    def _set_input_size(self, input_size: int | TensorShape) -> None:
+        if isinstance(input_size, TensorShape):
             raise TypeError("The input_size of a forward layer has to be of type int.")
 
         self._input_size = input_size
diff --git a/src/safeds/ml/nn/layers/_layer.py b/src/safeds/ml/nn/layers/_layer.py
index 058036688..63edfec5d 100644
--- a/src/safeds/ml/nn/layers/_layer.py
+++ b/src/safeds/ml/nn/layers/_layer.py
@@ -6,7 +6,7 @@
 if TYPE_CHECKING:
     from torch import nn
 
-    from safeds.ml.nn.typing import ModelImageSize
+    from safeds.ml.nn.typing import TensorShape
 
 
 class Layer(ABC):
@@ -20,16 +20,16 @@ def _get_internal_layer(self, **kwargs: Any) -> nn.Module:
 
     @property
     @abstractmethod
-    def input_size(self) -> int | ModelImageSize:
+    def input_size(self) -> TensorShape:
         pass  # pragma: no cover
 
     @property
     @abstractmethod
-    def output_size(self) -> int | ModelImageSize:
+    def output_size(self) -> TensorShape:
         pass  # pragma: no cover
 
     @abstractmethod
-    def _set_input_size(self, input_size: int | ModelImageSize) -> None:
+    def _set_input_size(self, input_size: TensorShape) -> None:
         pass  # pragma: no cover
 
     @abstractmethod
diff --git a/src/safeds/ml/nn/layers/_lstm_layer.py b/src/safeds/ml/nn/layers/_lstm_layer.py
index 330809474..f02e27242 100644
--- a/src/safeds/ml/nn/layers/_lstm_layer.py
+++ b/src/safeds/ml/nn/layers/_lstm_layer.py
@@ -5,7 +5,7 @@
 
 from safeds._utils import _structural_hash
 from safeds._validation import _check_bounds, _ClosedBound
-from safeds.ml.nn.typing import ModelImageSize
+from safeds.ml.nn.typing import TensorShape
 
 from ._layer import Layer
 
@@ -51,33 +51,33 @@ def _get_internal_layer(self, **kwargs: Any) -> nn.Module:
         return _InternalLSTMLayer(self._input_size, self._output_size, activation_function)
 
     @property
-    def input_size(self) -> int:
+    def input_size(self) -> TensorShape:
         """
         Get the input_size of this layer.
 
         Returns
         -------
         result:
-            The amount of values being passed into this layer.
+            A 1D TensorShape object containing the amount of values being passed into this layer.
         """
         if self._input_size is None:
             raise ValueError("The input_size is not yet set.")
-        return self._input_size
+        return TensorShape([self._input_size])
 
     @property
-    def output_size(self) -> int:
+    def output_size(self) -> TensorShape:
         """
         Get the output_size of this layer.
 
         Returns
         -------
         result:
-            The number of neurons in this layer.
+            A 1D TensorShape object containing the number of neurons in this layer.
         """
-        return self._output_size
+        return TensorShape([self._output_size])
 
-    def _set_input_size(self, input_size: int | ModelImageSize) -> None:
-        if isinstance(input_size, ModelImageSize):
+    def _set_input_size(self, input_size: int | TensorShape) -> None:
+        if isinstance(input_size, TensorShape):
             raise TypeError("The input_size of a forward layer has to be of type int.")
 
         self._input_size = input_size
diff --git a/src/safeds/ml/nn/typing/__init__.py b/src/safeds/ml/nn/typing/__init__.py
index 913ad6f65..08ea81601 100644
--- a/src/safeds/ml/nn/typing/__init__.py
+++ b/src/safeds/ml/nn/typing/__init__.py
@@ -6,12 +6,14 @@
 
 if TYPE_CHECKING:
     from ._model_image_size import ConstantImageSize, ModelImageSize, VariableImageSize
+    from ._tensor_shape import TensorShape
 
 apipkg.initpkg(
     __name__,
     {
         "ConstantImageSize": "._model_image_size:ConstantImageSize",
         "ModelImageSize": "._model_image_size:ModelImageSize",
+        "TensorShape": "._tensor_shape:TensorShape",
         "VariableImageSize": "._model_image_size:VariableImageSize",
     },
 )
@@ -19,5 +21,6 @@
 __all__ = [
     "ConstantImageSize",
     "ModelImageSize",
+    "TensorShape",
     "VariableImageSize",
 ]
diff --git a/src/safeds/ml/nn/typing/_model_image_size.py b/src/safeds/ml/nn/typing/_model_image_size.py
index b28ea5ed1..4157317fd 100644
--- a/src/safeds/ml/nn/typing/_model_image_size.py
+++ b/src/safeds/ml/nn/typing/_model_image_size.py
@@ -1,17 +1,18 @@
 from __future__ import annotations
 
 import sys
-from abc import ABC, abstractmethod
+from abc import abstractmethod
 from typing import TYPE_CHECKING, Self
 
 from safeds._utils import _structural_hash
 from safeds._validation import _check_bounds, _ClosedBound
+from safeds.ml.nn.typing._tensor_shape import TensorShape
 
 if TYPE_CHECKING:
     from safeds.data.image.containers import Image
 
 
-class ModelImageSize(ABC):
+class ModelImageSize(TensorShape):
     """
     A container for image size in neural networks.
 
@@ -38,6 +39,7 @@ def __init__(self, width: int, height: int, channel: int, *, _ignore_invalid_cha
         if not _ignore_invalid_channel and channel not in (1, 3, 4):
             raise ValueError(f"Channel {channel} is not a valid channel option. Use either 1, 3 or 4")
         _check_bounds("channel", channel, lower_bound=_ClosedBound(1))
+        super().__init__(dims=[width, height, channel])
 
         self._width = width
         self._height = height
diff --git a/src/safeds/ml/nn/typing/_tensor_shape.py b/src/safeds/ml/nn/typing/_tensor_shape.py
new file mode 100644
index 000000000..4ee867b1f
--- /dev/null
+++ b/src/safeds/ml/nn/typing/_tensor_shape.py
@@ -0,0 +1,59 @@
+from __future__ import annotations
+
+from safeds._utils import _structural_hash
+from safeds._validation import _check_bounds, _ClosedBound
+
+
+class TensorShape:
+    """
+    Initializes a TensorShape object with the given dimensions.
+
+    Parameters
+    ----------
+    dims:
+        A list of integers where each integer represents
+        the size of the tensor in a particular dimension.
+    """
+
+    def __init__(self, dims: list[int]) -> None:
+        self._dims = dims
+
+    def get_size(self, dimension: int | None = None) -> int | list[int]:
+        """
+        Return the size of the tensor in the specified dimension.
+
+        Parameters.
+        ----------
+        dimension:
+            The dimension index for which the size is to be retrieved.
+
+        Returns
+        -------
+            int: The size of the tensor in the specified dimension.
+
+        Raises
+        ------
+        OutOfBoundsError:
+            If the actual value is outside its expected range.
+        """
+        _check_bounds("dimension", dimension, lower_bound=_ClosedBound(0))
+        if dimension is not None and dimension >= self.dimensionality:
+            # TODO maybe add error message indicating that the dimension is out of range
+            return 0
+        if dimension is None:
+            return self._dims
+        return self._dims[dimension]
+
+    def __hash__(self) -> int:
+        return _structural_hash(self._dims)
+
+    @property
+    def dimensionality(self) -> int:
+        """
+        Returns the number of dimensions of the tensor.
+
+        Returns
+        -------
+            int: The number of dimensions of the tensor.
+        """
+        return len(self._dims)
diff --git a/tests/safeds/ml/nn/layers/test_flatten_layer.py b/tests/safeds/ml/nn/layers/test_flatten_layer.py
index 64db6127c..e30cef24b 100644
--- a/tests/safeds/ml/nn/layers/test_flatten_layer.py
+++ b/tests/safeds/ml/nn/layers/test_flatten_layer.py
@@ -14,7 +14,7 @@ def test_should_create_flatten_layer(self) -> None:
         input_size = ImageSize(10, 20, 30, _ignore_invalid_channel=True)
         layer._set_input_size(input_size)
         assert layer.input_size == input_size
-        assert layer.output_size == input_size.width * input_size.height * input_size.channel
+        assert layer.output_size.get_size(dimension=0) == input_size.width * input_size.height * input_size.channel
         assert isinstance(next(next(layer._get_internal_layer().modules()).children()), nn.Flatten)
 
     def test_should_raise_if_input_size_not_set(self) -> None:
diff --git a/tests/safeds/ml/nn/layers/test_forward_layer.py b/tests/safeds/ml/nn/layers/test_forward_layer.py
index 0ecd3bd05..06f37e7c1 100644
--- a/tests/safeds/ml/nn/layers/test_forward_layer.py
+++ b/tests/safeds/ml/nn/layers/test_forward_layer.py
@@ -83,7 +83,8 @@ def test_should_raise_if_output_size_out_of_bounds(output_size: int) -> None:
     ids=["one", "twenty"],
 )
 def test_should_return_output_size(output_size: int) -> None:
-    assert ForwardLayer(neuron_count=output_size).output_size == output_size
+    r = ForwardLayer(neuron_count=output_size).output_size.get_size(dimension=0)
+    assert r == output_size
 
 
 def test_should_raise_if_input_size_is_set_with_image_size() -> None:
diff --git a/tests/safeds/ml/nn/layers/test_gru_layer.py b/tests/safeds/ml/nn/layers/test_gru_layer.py
index 4a6f366e4..b5315c4b2 100644
--- a/tests/safeds/ml/nn/layers/test_gru_layer.py
+++ b/tests/safeds/ml/nn/layers/test_gru_layer.py
@@ -71,7 +71,7 @@ def test_should_raise_if_output_size_out_of_bounds(output_size: int) -> None:
     ids=["one", "twenty"],
 )
 def test_should_raise_if_output_size_doesnt_match(output_size: int) -> None:
-    assert GRULayer(neuron_count=output_size).output_size == output_size
+    assert GRULayer(neuron_count=output_size).output_size.get_size(dimension=0) == output_size
 
 
 def test_should_raise_if_input_size_is_set_with_image_size() -> None:
@@ -170,7 +170,7 @@ def test_should_assert_that_layer_size_is_greater_than_normal_object(layer: GRUL
 def test_set_input_size() -> None:
     layer = GRULayer(1)
     layer._set_input_size(3)
-    assert layer.input_size == 3
+    assert layer.input_size.get_size(dimension=0) == 3
 
 
 def test_input_size_should_raise_error() -> None:
diff --git a/tests/safeds/ml/nn/layers/test_lstm_layer.py b/tests/safeds/ml/nn/layers/test_lstm_layer.py
index 8d58e5dd8..48726e525 100644
--- a/tests/safeds/ml/nn/layers/test_lstm_layer.py
+++ b/tests/safeds/ml/nn/layers/test_lstm_layer.py
@@ -83,7 +83,7 @@ def test_should_raise_if_output_size_out_of_bounds(output_size: int) -> None:
     ids=["one", "twenty"],
 )
 def test_should_raise_if_output_size_doesnt_match(output_size: int) -> None:
-    assert LSTMLayer(neuron_count=output_size).output_size == output_size
+    assert LSTMLayer(neuron_count=output_size).output_size.get_size(dimension=0) == output_size
 
 
 def test_should_raise_if_input_size_is_set_with_image_size() -> None:
diff --git a/tests/safeds/ml/nn/typing/test_tensor_shape.py b/tests/safeds/ml/nn/typing/test_tensor_shape.py
new file mode 100644
index 000000000..f1825d911
--- /dev/null
+++ b/tests/safeds/ml/nn/typing/test_tensor_shape.py
@@ -0,0 +1,43 @@
+import pytest
+from safeds.exceptions import OutOfBoundsError
+from safeds.ml.nn.typing import TensorShape
+
+
+def test_dims() -> None:
+    dims = [2, 3, 4]
+    ts = TensorShape(dims)
+    assert ts._dims == dims
+
+
+def test_dimensionality() -> None:
+    dims = [2, 3, 4]
+    ts = TensorShape(dims)
+    assert ts.dimensionality == 3
+
+
+def test_get_size_no_dimension() -> None:
+    dims = [2, 3, 4]
+    ts = TensorShape(dims)
+    assert ts.get_size() == dims
+
+
+def test_get_size_specific_dimension() -> None:
+    dims = [2, 3, 4]
+    ts = TensorShape(dims)
+    assert ts.get_size(0) == 2
+    assert ts.get_size(1) == 3
+    assert ts.get_size(2) == 4
+
+
+def test_get_size_out_of_bounds_dimension() -> None:
+    dims = [2, 3, 4]
+    ts = TensorShape(dims)
+    with pytest.raises(OutOfBoundsError):
+        ts.get_size(-1)
+
+
+def test_hash() -> None:
+    dims = [2, 3, 4]
+    ts1 = TensorShape(dims)
+    ts2 = TensorShape(dims)
+    assert hash(ts1) == hash(ts2)