diff --git a/aleksis/core/apps.py b/aleksis/core/apps.py
index a3efe2ce8fc43d490a90de14f5b869ccc8e45d85..4e33bf83fbe4c5e18032fbd087dc91281968b622 100644
--- a/aleksis/core/apps.py
+++ b/aleksis/core/apps.py
@@ -4,6 +4,9 @@ import django.apps
 from django.contrib.auth.signals import user_logged_in
 from django.http import HttpRequest
 
+from dynamic_preferences.registries import preference_models
+
+from .registries import group_preferences_registry, person_preferences_registry, site_preferences_registry
 from .signals import clean_scss
 from .util.apps import AppConfig
 from .util.core_helpers import has_person
@@ -27,6 +30,15 @@ class CoreConfig(AppConfig):
         ([2019, 2020], "Tom Teichler", "tom.teichler@teckids.org"),
     )
 
+    def ready(self):
+        SitePreferenceModel = self.get_model('SitePreferenceModel')
+        PersonPreferenceModel = self.get_model('PersonPreferenceModel')
+        GroupPreferenceModel = self.get_model('GroupPreferenceModel')
+
+        preference_models.register(SitePreferenceModel, site_preferences_registry)
+        preference_models.register(PersonPreferenceModel, person_preferences_registry)
+        preference_models.register(GroupPreferenceModel, group_preferences_registry)
+
     def preference_updated(
         self,
         sender: Any,
diff --git a/aleksis/core/models.py b/aleksis/core/models.py
index f8845671c419e500bc2b25d0fdcf9cd7b6272c09..85ef2c2e5fe1877d6a98eab5fe82404960b0d247 100644
--- a/aleksis/core/models.py
+++ b/aleksis/core/models.py
@@ -5,12 +5,14 @@ from django.contrib.auth import get_user_model
 from django.contrib.auth.models import Group as DjangoGroup
 from django.contrib.contenttypes.fields import GenericForeignKey
 from django.contrib.contenttypes.models import ContentType
+from django.contrib.sites.models import Site
 from django.db import models
 from django.db.models import QuerySet
 from django.forms.widgets import Media
 from django.urls import reverse
 from django.utils import timezone
 from django.utils.translation import gettext_lazy as _
+from dynamic_preferences.models import PerInstancePreferenceModel
 from image_cropping import ImageCropField, ImageRatioField
 from phonenumber_field.modelfields import PhoneNumberField
 from polymorphic.models import PolymorphicModel
@@ -25,69 +27,6 @@ from dynamic_preferences.registries import global_preferences_registry
 global_preferences = global_preferences_registry.manager()
 
 
-class School(ExtensibleModel):
-    """A school that will have many other objects linked to it.
-    AlekSIS has multi-tenant support by linking all objects to a school,
-    and limiting all features to objects related to the same school as the
-    currently logged-in user.
-    """
-
-    name = models.CharField(verbose_name=_("Name"), max_length=255)
-    name_official = models.CharField(
-        verbose_name=_("Official name"),
-        max_length=255,
-        help_text=_("Official name of the school, e.g. as given by supervisory authority"),
-    )
-
-    logo = ImageCropField(verbose_name=_("School logo"), blank=True, null=True)
-    logo_cropping = ImageRatioField("logo", "600x600", size_warning=True)
-
-    @classmethod
-    def get_default(cls):
-        return cls.objects.first()
-
-    @property
-    def current_term(self):
-        return SchoolTerm.objects.get(current=True)
-
-    class Meta:
-        ordering = ["name", "name_official"]
-        verbose_name = _("School")
-        verbose_name_plural = _("Schools")
-
-
-class SchoolTerm(ExtensibleModel):
-    """ Information about a term (limited time frame) that data can
-    be linked to.
-    """
-
-    caption = models.CharField(verbose_name=_("Visible caption of the term"), max_length=255)
-
-    date_start = models.DateField(verbose_name=_("Effective start date of term"), null=True)
-    date_end = models.DateField(verbose_name=_("Effective end date of term"), null=True)
-
-    current = models.NullBooleanField(default=None, unique=True)
-
-    def save(self, *args, **kwargs):
-        if self.current is False:
-            self.current = None
-        super().save(*args, **kwargs)
-
-    @classmethod
-    def maintain_default_data(cls):
-        if not cls.objects.filter(current=True).exists():
-            if cls.objects.exists():
-                term = cls.objects.latest('date_start')
-                term.current=True
-                term.save()
-            else:
-                cls.objects.create(date_start=date.today(), current=True)
-
-    class Meta:
-        verbose_name = _("School term")
-        verbose_name_plural = _("School terms")
-
-
 class Person(ExtensibleModel):
     """ A model describing any person related to a school, including, but not
     limited to, students, teachers and guardians (parents).
@@ -586,3 +525,15 @@ class GlobalPermissions(ExtensibleModel):
             ("impersonate", _("Can impersonate")),
             ("search", _("Can use search")),
         )
+
+
+class SitePreferenceModel(PerInstancePreferenceModel):
+    instance = models.ForeignKey(Site)
+
+
+class PersonPreferenceModel(PerInstancePreferenceModel):
+    instance = models.ForeignKey(Person)
+
+
+class GroupPreferenceModel(PerInstancePreferenceModel):
+    instance = models.ForeignKey(Group)
diff --git a/aleksis/core/preferences.py b/aleksis/core/preferences.py
index be34422b0ac35b49b7cc587f719e5946797d76ba..cd4255fb5b6bb5915324904260124fa46fbbd8fe 100644
--- a/aleksis/core/preferences.py
+++ b/aleksis/core/preferences.py
@@ -6,11 +6,13 @@ from colorfield.widgets import ColorWidget
 from dynamic_preferences.types import BooleanPreference, ChoicePreference, StringPreference
 from dynamic_preferences.preferences import Section
 from dynamic_preferences.registries import global_preferences_registry
-from dynamic_preferences.users.registries import user_preferences_registry
 
+from .registries import group_preferences_registry, person_preferences_registry, site_preferences_registry
 from .util.notifications import get_notification_choices_lazy
 
+
 general = Section("general")
+school = Section("school")
 theme = Section("theme")
 mail = Section("mail")
 notification = Section("notification")
@@ -18,7 +20,7 @@ footer = Section("footer")
 account = Section("account")
 
 
-@global_preferences_registry.register
+@site_preferences_registry.register
 class SiteTitle(StringPreference):
     section = general
     name = "title"
@@ -27,7 +29,7 @@ class SiteTitle(StringPreference):
     verbose_name = _("Site title")
 
 
-@global_preferences_registry.register
+@site_preferences_registry.register
 class SiteDescription(StringPreference):
     section = general
     name = "description"
@@ -36,7 +38,7 @@ class SiteDescription(StringPreference):
     verbose_name = _("Site description")
 
 
-@global_preferences_registry.register
+@site_preferences_registry.register
 class ColourPrimary(StringPreference):
     section = theme
     name = "primary"
@@ -45,7 +47,7 @@ class ColourPrimary(StringPreference):
     verbose_name = _("Primary colour")
 
 
-@global_preferences_registry.register
+@site_preferences_registry.register
 class ColourSecondary(StringPreference):
     section = theme
     name = "secondary"
@@ -54,7 +56,7 @@ class ColourSecondary(StringPreference):
     verbose_name = _("Secondary colour")
 
 
-@global_preferences_registry.register
+@site_preferences_registry.register
 class MailOutName(StringPreference):
     section = mail
     name = "name"
@@ -63,7 +65,7 @@ class MailOutName(StringPreference):
     verbose_name = _("Mail out name")
 
 
-@global_preferences_registry.register
+@site_preferences_registry.register
 class MailOut(StringPreference):
     section = mail
     name = "address"
@@ -73,7 +75,7 @@ class MailOut(StringPreference):
     field_class = EmailField
 
 
-@global_preferences_registry.register
+@site_preferences_registry.register
 class PrivacyURL(StringPreference):
     section = footer
     name = "privacy_url"
@@ -83,7 +85,7 @@ class PrivacyURL(StringPreference):
     field_class = URLField
 
 
-@global_preferences_registry.register
+@site_preferences_registry.register
 class ImprintURL(StringPreference):
     section = footer
     name = "imprint_url"
@@ -93,7 +95,7 @@ class ImprintURL(StringPreference):
     field_class = URLField
 
 
-@user_preferences_registry.register
+@person_preferences_registry.register
 class AdressingNameFormat(ChoicePreference):
     section = notification
     name = "addressing_name_format"
@@ -108,7 +110,7 @@ class AdressingNameFormat(ChoicePreference):
               )
 
 
-@user_preferences_registry.register
+@person_preferences_registry.register
 class NotificationChannels(ChoicePreference):
     # FIXME should be a MultipleChoicePreference
     section = notification
@@ -119,10 +121,28 @@ class NotificationChannels(ChoicePreference):
     choices = get_notification_choices_lazy()
 
 
-@global_preferences_registry.register
+@site_preferences_registry.register
 class PrimaryGroupPattern(StringPreference):
     section = account
     name = "primary_group_pattern"
     default = ""
     required = False
     verbose_name = _("Regular expression to match primary group, e.g. '^Class .*'")
+
+
+@site_preferences_registry.register
+class SchoolName(StringPreference):
+    section = school
+    name = "name"
+    default = ""
+    required = False
+    verbose_name = _("Display name of the school")
+
+
+@site_preferences_registry.register
+class SchoolNameOfficial(StringPreference):
+    section = school
+    name = "name_official"
+    default = ""
+    required = False
+    verbose_name = _("Official name of the school, e.g. as given by supervisory authority")
diff --git a/aleksis/core/registries.py b/aleksis/core/registries.py
new file mode 100644
index 0000000000000000000000000000000000000000..eab1cb333336bc416a09a73931ff0bdcec3903ae
--- /dev/null
+++ b/aleksis/core/registries.py
@@ -0,0 +1,18 @@
+from dynamic_preferences.registries import PerInstancePreferenceRegistry
+
+
+class SitePreferenceRegistry(PerInstancePreferenceRegistry):
+    pass
+
+
+class PersonPreferenceRegistry(PerInstancePreferenceRegistry):
+    pass
+
+
+class GroupPreferenceRegistry(PerInstancePreferenceRegistry):
+    pass
+
+
+site_preferences_registry = SitePreferenceRegistry()
+person_preferences_registry = PersonPreferenceRegistry()
+group_preferences_registry = GroupPreferenceRegistry()
diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py
index 56acf80295546ac73cbffd4bc0e36770d8bb3687..7a567e94f86a3e8784b9bcabcdeb3eb6bbe55c65 100644
--- a/aleksis/core/util/core_helpers.py
+++ b/aleksis/core/util/core_helpers.py
@@ -93,10 +93,11 @@ def lazy_preference(section: str, name: str) -> Callable[[str, str], Any]:
     """
 
     def _get_preference(section: str, name: str) -> Any:
-        from dynamic_preferences.registries import global_preferences_registry  # noqa
-        global_preferences = global_preferences_registry.manager()
+        from ..registries import site_preferences_registry  # noqa
 
-        return global_preferences["%s__%s" % (section, name)]
+        site_preferences = site_preferences_registry.manager()
+
+        return site_preferences["%s__%s" % (section, name)]
 
     # The type is guessed from the default value to improve lazy()'s behaviour
     # FIXME Reintroduce the behaviour described above