diff --git a/biscuit/core/mixins.py b/biscuit/core/mixins.py
index 684e9f401e146eb8783f824454ebe6aeaaac4fc3..8b31557cf9b23ca15a4bc6ce5d3979efc4f954fa 100644
--- a/biscuit/core/mixins.py
+++ b/biscuit/core/mixins.py
@@ -1,3 +1,5 @@
+from typing import Any, Callable, Optional
+
 from django.contrib.contenttypes.models import ContentType
 from django.db import models
 from django.db.models import QuerySet
@@ -7,6 +9,30 @@ from easyaudit.models import CRUDEvent
 from .util.core_helpers import get_current_school
 
 
+class ExtensibleModel(object):
+    """ Mixin that adds class methods for glrofied monkey-patching. """
+
+    @classmethod
+    def property(cls, func: Callable[[], Any], name: Optional[str] = None) -> None:
+        """ Adds the passed callable as a property. """
+
+        # Decide the name for the property
+        if name is None:
+            prop_name = func.__name__
+        else:
+            if name.isidentifier():
+                prop_name = name
+            else:
+                raise ValueError('%s is not a valid name.' % name)
+
+        # Verify that property name does not clash with other names in the class
+        if hasattr(cls, prop_name):
+            raise ValueError('%s already used.' % prop_name)
+
+        # Add function wrapped in property decorator if we got here
+        setattr(cls, prop_name, property(func))
+
+
 class SchoolRelated(models.Model):
     class Meta:
         abstract = True
diff --git a/biscuit/core/models.py b/biscuit/core/models.py
index d726602eb2b72bab7d49543b073b556afa5d8607..63e4bde6e4d99c5f09c2a2ff75afacab50bc0f83 100644
--- a/biscuit/core/models.py
+++ b/biscuit/core/models.py
@@ -7,7 +7,7 @@ from django.utils.translation import ugettext_lazy as _
 from image_cropping import ImageCropField, ImageRatioField
 from phonenumber_field.modelfields import PhoneNumberField
 
-from .mixins import SchoolRelated
+from .mixins import ExtensibleModel, SchoolRelated
 
 
 class School(models.Model):
@@ -42,9 +42,9 @@ class SchoolTerm(SchoolRelated):
         'Effective start date of term'), null=True)
     date_end = models.DateField(verbose_name=_(
         'Effective end date of term'), null=True)
-    
 
-class Person(SchoolRelated):
+
+class Person(SchoolRelated, ExtensibleModel):
     """ A model describing any person related to a school, including, but not
     limited to, students, teachers and guardians (parents).
     """
@@ -132,7 +132,7 @@ class Person(SchoolRelated):
         return self.full_name
 
 
-class Group(SchoolRelated):
+class Group(SchoolRelated, ExtensibleModel):
     """Any kind of group of persons in a school, including, but not limited
     classes, clubs, and the like.
     """