diff --git a/scipost_django/graphs/forms.py b/scipost_django/graphs/forms.py
index 1a2ceb9e4a786c709e02a96dbcbdecf5a1e0a31c..8edd3cae909337a9adb2d5f4a4cd0d0706c9cda7 100644
--- a/scipost_django/graphs/forms.py
+++ b/scipost_django/graphs/forms.py
@@ -9,7 +9,7 @@ from graphs.graphs.plotter import ModelFieldPlotter
 from .graphs import ALL_PLOTTERS, ALL_PLOT_KINDS, AVAILABLE_MPL_THEMES
 
 from crispy_forms.helper import FormHelper, Layout
-from crispy_forms.layout import Div, Field
+from crispy_forms.layout import LayoutObject, Div, Field
 
 
 class ModelFieldPlotterSelectForm(forms.Form):
@@ -98,7 +98,8 @@ class PlotOptionsForm(forms.Form):
 
         def get_layout_field_names(layout):
             """Recurse through a layout to get all field names."""
-            field_names = []
+            field_names: list[str] = []
+            field: LayoutObject | str
             for field in layout:
                 if isinstance(field, str):
                     field_names.append(field)
@@ -106,6 +107,25 @@ class PlotOptionsForm(forms.Form):
                     field_names.extend(get_layout_field_names(field.fields))
             return field_names
 
+        def prefix_layout_fields(prefix: str, field: LayoutObject):
+            """
+            Recursively prefix the fields in a layout.
+            Return type is irrelevant, as it modifies the argument directly.
+            """
+
+            if (contained_fields := getattr(field, "fields", None)) is None:
+                return
+
+            # If the crispy field is a Field type with a single string identifier, prefix it
+            if (
+                isinstance(field, Field)
+                and len(contained_fields) == 1
+                and isinstance(field_key := contained_fields[0], str)
+            ):
+                field.fields = [prefix + field_key]
+            else:
+                [prefix_layout_fields(prefix, f) for f in contained_fields]
+
         # Iterate over all forms and construct the form layout
         # either by extending the layout with the preferred layout from the object class
         # or by creating a row with all fields that are not already in the layout
@@ -121,10 +141,18 @@ class PlotOptionsForm(forms.Form):
                 layout.append(Div(Field(principal_field_name), css_class="col-12"))
 
                 row_constructor = getattr(
-                    object_class, "get_plot_options_form_layout_row_content"
+                    object_class, "get_plot_options_form_layout_row_content", None
                 )
                 if row_constructor:
-                    layout.extend(row_constructor())
+                    try:
+                        object_class_prefix = object_class.Options.prefix or ""
+                    except AttributeError:
+                        object_class_prefix = ""
+
+                    fields = row_constructor()
+                    # In-place prefixing of the layout-field names
+                    prefix_layout_fields(object_class_prefix, fields)
+                    layout.extend(fields)
 
             layout.extend(
                 [
diff --git a/scipost_django/graphs/graphs/plotkind.py b/scipost_django/graphs/graphs/plotkind.py
index e7f538c1045f49133399f156c39abd877684847d..270db58ec3b734e24e9ff49f73682c9b13542178 100644
--- a/scipost_django/graphs/graphs/plotkind.py
+++ b/scipost_django/graphs/graphs/plotkind.py
@@ -7,7 +7,7 @@ from matplotlib.figure import Figure
 import pandas as pd
 
 from .options import BaseOptions
-from crispy_forms.layout import Layout, Div, Field
+from crispy_forms.layout import LayoutObject, Layout, Div, Field
 
 from typing import TYPE_CHECKING, Any
 
@@ -84,7 +84,7 @@ class PlotKind:
         ax.axis("off")
 
     @classmethod
-    def get_plot_options_form_layout_row_content(cls):
+    def get_plot_options_form_layout_row_content(cls) -> LayoutObject:
         return Div()
 
 
@@ -140,36 +140,12 @@ class TimelinePlot(PlotKind):
 
     @classmethod
     def get_plot_options_form_layout_row_content(cls):
-        layout = Layout(
+        return Layout(
             Div(Field("y_key"), css_class="col-12"),
             Div(Field("x_lim_min"), css_class="col-6"),
             Div(Field("x_lim_max"), css_class="col-6"),
         )
 
-        # Prefix every field in the layout with the prefix
-        def prefix_field(field):
-            """
-            Recursively prefix the fields in a layout.
-            Return type is irrelevant, as it modifies the argument directly.
-            """
-            contained_fields = getattr(field, "fields", None)
-            if contained_fields is None:
-                return
-
-            # If the crispy field is a Field type with a single string identifier, prefix it
-            if (
-                isinstance(field, Field)
-                and len(contained_fields) == 1
-                and isinstance(field_key := contained_fields[0], str)
-            ):
-                field.fields = [cls.Options.prefix + field_key]
-            else:
-                return [prefix_field(f) for f in contained_fields]
-
-        prefix_field(layout)
-
-        return layout
-
 
 class MapPlot(PlotKind):
     name = "map"
@@ -303,31 +279,7 @@ class MapPlot(PlotKind):
 
     @classmethod
     def get_plot_options_form_layout_row_content(cls):
-        layout = Layout(
+        return Layout(
             Div(Field("agg_func"), css_class="col-6"),
             Div(Field("agg_key"), css_class="col-6"),
         )
-
-        # Prefix every field in the layout with the prefix
-        def prefix_field(field):
-            """
-            Recursively prefix the fields in a layout.
-            Return type is irrelevant, as it modifies the argument directly.
-            """
-            contained_fields = getattr(field, "fields", None)
-            if contained_fields is None:
-                return
-
-            # If the crispy field is a Field type with a single string identifier, prefix it
-            if (
-                isinstance(field, Field)
-                and len(contained_fields) == 1
-                and isinstance(field_key := contained_fields[0], str)
-            ):
-                field.fields = [cls.Options.prefix + field_key]
-            else:
-                return [prefix_field(f) for f in contained_fields]
-
-        prefix_field(layout)
-
-        return layout