diff --git a/bricktracker/rebrickable_set.py b/bricktracker/rebrickable_set.py
index fbf10f1..d2878d6 100644
--- a/bricktracker/rebrickable_set.py
+++ b/bricktracker/rebrickable_set.py
@@ -11,10 +11,10 @@ from .parser import parse_set
 from .rebrickable import Rebrickable
 from .rebrickable_image import RebrickableImage
 from .record import BrickRecord
+from .theme import BrickTheme
 from .theme_list import BrickThemeList
 if TYPE_CHECKING:
     from .socket import BrickSocket
-    from .theme import BrickTheme
 
 logger = logging.getLogger(__name__)
 
@@ -66,7 +66,13 @@ class RebrickableSet(BrickRecord):
         if not hasattr(self.fields, 'theme_id'):
             self.fields.theme_id = 0
 
-        self.theme = BrickThemeList().get(self.fields.theme_id)
+        if not hasattr(self.fields, 'theme_name'):
+            self.fields.theme_name = None
+
+        self.theme = BrickThemeList().get(
+            str(self.fields.theme_id),
+            name=self.fields.theme_name
+        )
 
         # Resolve instructions
         if self.resolve_instructions:
diff --git a/bricktracker/set.py b/bricktracker/set.py
index 28f0341..893acc0 100644
--- a/bricktracker/set.py
+++ b/bricktracker/set.py
@@ -1,11 +1,12 @@
 import logging
+from sqlite3 import Row
 import traceback
 from typing import Any, Self, TYPE_CHECKING
 from uuid import uuid4
 
 from flask import current_app, url_for
 
-from .exceptions import DatabaseException, NotFoundException
+from .exceptions import DatabaseException, ErrorException, NotFoundException
 from .minifigure_list import BrickMinifigureList
 from .part_list import BrickPartList
 from .rebrickable_set import RebrickableSet
@@ -121,6 +122,29 @@ class BrickSet(RebrickableSet):
 
         return True
 
+    # Ingest a set
+    def ingest(self, record: Row | dict[str, Any], /):
+        # Super charge the record with theme override
+        if 'theme' in record.keys() and record['theme'] is not None:
+            if isinstance(record, Row):
+                record = dict(record)
+
+            record['theme_id'] = record['theme']
+            record['theme_name'] = record['theme']
+
+        super().ingest(record)
+
+    # A identifier for HTML component
+    def html_id(self, prefix: str | None = None, /) -> str:
+        components: list[str] = []
+
+        if prefix is not None:
+            components.append(prefix)
+
+        components.append(self.fields.id)
+
+        return '-'.join(components)
+
     # Minifigures
     def minifigures(self, /) -> BrickMinifigureList:
         return BrickMinifigureList().from_set(self)
@@ -185,6 +209,36 @@ class BrickSet(RebrickableSet):
                 id=self.fields.id,
             ))
 
+    # Update theme
+    def update_theme(self, json: Any | None, /) -> None:
+        theme: str | None = json.get('value', '')  # type: ignore
+
+        # We need a string
+        try:
+            theme = str(theme)
+            theme = theme.strip()
+        except Exception:
+            raise ErrorException('"{theme}" is not a valid string'.format(
+                theme=theme
+            ))
+
+        if theme == '':
+            theme = None
+
+        self.fields.theme = theme
+
+        # Update the status
+        rows, _ = BrickSQL().execute_and_commit(
+            'set/update/theme',
+            parameters=self.sql_parameters()
+        )
+
+        if rows != 1:
+            raise DatabaseException('Could not update the theme override for set {set} ({id})'.format(  # noqa: E501
+                set=self.fields.set,
+                id=self.fields.id,
+            ))
+
     # Self url
     def url(self, /) -> str:
         return url_for('set.details', id=self.fields.id)
@@ -217,3 +271,10 @@ class BrickSet(RebrickableSet):
             'set.refresh',
             id=self.fields.id,
         )
+
+    # Compute the url for the theme override
+    def url_for_theme(self, /) -> str:
+        return url_for(
+            'set.update_theme',
+            id=self.fields.id,
+        )
diff --git a/bricktracker/sql/set/base/base.sql b/bricktracker/sql/set/base/base.sql
index 8b1f4c8..7bc1bc3 100644
--- a/bricktracker/sql/set/base/base.sql
+++ b/bricktracker/sql/set/base/base.sql
@@ -1,5 +1,6 @@
 SELECT
     {% block id %}{% endblock %}
+    "bricktracker_sets"."theme",
     "rebrickable_sets"."set",
     "rebrickable_sets"."number",
     "rebrickable_sets"."version",
diff --git a/bricktracker/sql/set/update/theme.sql b/bricktracker/sql/set/update/theme.sql
new file mode 100644
index 0000000..1d884ed
--- /dev/null
+++ b/bricktracker/sql/set/update/theme.sql
@@ -0,0 +1,3 @@
+UPDATE "bricktracker_sets"
+SET "theme" = :theme
+WHERE "bricktracker_sets"."id" IS NOT DISTINCT FROM :id
diff --git a/bricktracker/theme.py b/bricktracker/theme.py
index 3ee1068..df677f4 100644
--- a/bricktracker/theme.py
+++ b/bricktracker/theme.py
@@ -1,14 +1,14 @@
 # Lego set theme
 class BrickTheme(object):
-    id: int
+    id: str
     name: str
-    parent: int | None
+    parent: str | None
 
-    def __init__(self, id: str | int, name: str, parent: str | None = None, /):
-        self.id = int(id)
+    def __init__(self, id: str, name: str, parent: str | None = None, /):
+        self.id = id
         self.name = name
 
         if parent is not None and parent != '':
-            self.parent = int(parent)
+            self.parent = parent
         else:
             self.parent = None
diff --git a/bricktracker/theme_list.py b/bricktracker/theme_list.py
index 22cac8e..af1667e 100644
--- a/bricktracker/theme_list.py
+++ b/bricktracker/theme_list.py
@@ -17,7 +17,7 @@ logger = logging.getLogger(__name__)
 
 # Lego sets themes
 class BrickThemeList(object):
-    themes: dict[int, BrickTheme]
+    themes: dict[str, BrickTheme]
     mtime: datetime | None
     size: int | None
     exception: Exception | None
@@ -57,12 +57,15 @@ class BrickThemeList(object):
                 BrickThemeList.mtime = None
 
     # Get a theme
-    def get(self, id: int, /) -> BrickTheme:
+    def get(self, id: str, /, *, name: str | None = None) -> BrickTheme:
         # Seed a fake entry if missing
         if id not in self.themes:
+            if name is None:
+                name = 'Unknown ({id})'.format(id=id)
+
             BrickThemeList.themes[id] = BrickTheme(
                 id,
-                'Unknown ({id})'.format(id=id)
+                name,
             )
 
         return self.themes[id]
diff --git a/bricktracker/views/set.py b/bricktracker/views/set.py
index 809d46b..59289ff 100644
--- a/bricktracker/views/set.py
+++ b/bricktracker/views/set.py
@@ -167,3 +167,22 @@ def refresh(*, id: str) -> str:
         namespace=current_app.config['SOCKET_NAMESPACE'],
         messages=MESSAGES
     )
+
+
+# Change the theme override
+@set_page.route('/<id>/theme', methods=['POST'])
+@login_required
+@exception_handler(__file__, json=True)
+def update_theme(*, id: str) -> Response:
+    brickset = BrickSet().select_light(id)
+
+    brickset.update_theme(request.json)
+
+    # Info
+    logger.info('Set {set} ({id}): theme override changed to "{theme}"'.format(  # noqa: E501
+        set=brickset.fields.set,
+        id=brickset.fields.id,
+        theme=brickset.fields.theme,
+    ))
+
+    return jsonify({'value': brickset.fields.theme})
diff --git a/templates/set/management.html b/templates/set/management.html
index b27c9d0..b299972 100644
--- a/templates/set/management.html
+++ b/templates/set/management.html
@@ -1,5 +1,11 @@
 {% if g.login.is_authenticated() %}
-{{ accordion.header('Management', 'management', 'set-details', icon='settings-4-line', class='text-end') }}
+{{ accordion.header('Management', 'management', 'set-details', expanded=true, icon='settings-4-line') }}
+    <h5>Theme override</h5>
+    <p>
+      You can override the current theme ({{ badge.theme(item.theme.name, solo=solo, last=last) }}) with any string you want.
+      {{ form.input('Theme', item.fields.id, item.html_id('theme'), item.url_for_theme(), item.fields.theme, all=all, read_only=read_only) }}
+    </p>
+    <h5 class="border-bottom">Data</h5>
     <a href="{{ item.url_for_refresh() }}" class="btn btn-primary" role="button"><i class="ri-refresh-line"></i> Refresh the set data</a>
 {{ accordion.footer() }}
 {% endif %}