diff --git a/aleksis/apps/matrix/model_extensions.py b/aleksis/apps/matrix/model_extensions.py
deleted file mode 100644
index 70753101ed9a6a7997802a889876c2c6886bb1a9..0000000000000000000000000000000000000000
--- a/aleksis/apps/matrix/model_extensions.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from django.utils.translation import gettext_lazy as _
-
-from jsonstore import CharField
-
-from aleksis.core.models import Group, Person
-
-
-Person.field(matrix_id=CharField(verbose_name=_("Matrix ID")))
-Group.field(matrix_room_id=CharField(verbose_name=_("Matrix room ID")))
diff --git a/aleksis/apps/matrix/models.py b/aleksis/apps/matrix/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..3b3dd684fc645a4c91b5fa6444e855ef8ec00253
--- /dev/null
+++ b/aleksis/apps/matrix/models.py
@@ -0,0 +1,52 @@
+from django.db import models
+from django.utils.translation import gettext_lazy as _
+
+from aleksis.core.mixins import ExtensibleModel, ExtensiblePolymorphicModel
+from aleksis.core.models import Group, Person
+
+
+class MatrixProfile(ExtensibleModel):
+    """Model for a Matrix profile."""
+
+    matrix_id = models.CharField(verbose_name=_("Matrix ID"), unique=True)
+    person = models.OneToOneField(
+        Person,
+        on_delete=models.CASCADE,
+        verbose_name=_("Person"),
+        null=True,
+        blank=True,
+        related_name="matrix_profile",
+    )
+
+    class Meta:
+        verbose_name = _("Matrix profile")
+        verbose_name_plural = _("Matrix profiles")
+
+
+class MatrixRoom(ExtensiblePolymorphicModel):
+    """Model for a Matrix room."""
+
+    room_id = models.CharField(verbose_name=_("Room ID"), unique=True)
+    alias = models.CharField(verbose_name=_("Alias"), unique=True, blank=True, null=True)
+    group = models.ForeignKey(
+        Group,
+        on_delete=models.CASCADE,
+        verbose_name=_("Group"),
+        null=True,
+        blank=True,
+        related_name="matrix_spaces",
+    )
+
+    class Meta:
+        verbose_name = _("Matrix room")
+        verbose_name_plural = _("Matrix rooms")
+
+
+class MatrixSpace(MatrixRoom):
+    children = models.ManyToManyField(
+        to=MatrixRoom, verbose_name=_("Child rooms/spaces"), blank=True, related_name="parents"
+    )
+
+    class Meta:
+        verbose_name = _("Matrix space")
+        verbose_name_plural = _("Matrix spaces")