diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 6d4912a89480e5b5e26d6c9630bd7f5750351aff..28544205f693dda1d9b5f25f32fbb0140d32b717 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -28,6 +28,7 @@ Added
 * [Dev] Managed models for instances handled by other apps.
 * [Dev] Upload slot sytem for out-of-band uploads in GraphQL clients
 * Generic endpoint for retrieving objects as JSON
+* [Dev] Base model for organisational entities (external companies, associations,…)
 
 Changed
 ~~~~~~~
diff --git a/aleksis/core/admin.py b/aleksis/core/admin.py
index 45de07f84a8a9fa4a90a621be307e7cf1e730cd9..8084e2e3e62773298d09f74f605382256ab534c3 100644
--- a/aleksis/core/admin.py
+++ b/aleksis/core/admin.py
@@ -14,6 +14,7 @@ from .models import (
     DataCheckResult,
     Group,
     Notification,
+    Organisation,
     Person,
 )
 
@@ -40,3 +41,4 @@ admin.site.register(Announcement, AnnouncementAdmin)
 admin.site.register(DataCheckResult)
 admin.site.register(Person, GuardedVersionAdmin)
 admin.site.register(Group, GuardedVersionAdmin)
+admin.site.register(Organisation)
diff --git a/aleksis/core/migrations/0053_create_organisation_model.py b/aleksis/core/migrations/0053_create_organisation_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..af2ed7ba16ca9b6b06009abe48fb0bfd6134f450
--- /dev/null
+++ b/aleksis/core/migrations/0053_create_organisation_model.py
@@ -0,0 +1,74 @@
+# Generated by Django 4.1.7 on 2023-03-23 18:30
+
+import django.contrib.sites.managers
+from django.db import migrations, models
+import django.db.models.deletion
+import aleksis.core.managers
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("sites", "0002_alter_domain_unique"),
+        ("core", "0052_site_related_name"),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="Organisation",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
+                    ),
+                ),
+                ("extended_data", models.JSONField(default=dict, editable=False)),
+                ("name", models.CharField(max_length=255, verbose_name="Name")),
+                ("email", models.CharField(max_length=255, verbose_name="Email")),
+                (
+                    "related_group",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="core.group",
+                        verbose_name="Related group",
+                    ),
+                ),
+                (
+                    "site",
+                    models.ForeignKey(
+                        default=1,
+                        editable=False,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="+",
+                        to="sites.site",
+                    ),
+                ),
+            ],
+            options={
+                "abstract": False,
+            },
+            managers=[
+                ("objects", django.contrib.sites.managers.CurrentSiteManager()),
+            ],
+        ),
+        migrations.AlterModelOptions(
+            name="organisation",
+            options={"verbose_name": "Organisation", "verbose_name_plural": "Organisations"},
+        ),
+        migrations.AlterModelManagers(
+            name="organisation",
+            managers=[
+                ("objects", aleksis.core.managers.AlekSISBaseManager()),
+            ],
+        ),
+        migrations.AddField(
+            model_name="organisation",
+            name="managed_by_app_label",
+            field=models.CharField(
+                blank=True,
+                editable=False,
+                max_length=255,
+                verbose_name="App label of app responsible for managing this instance",
+            ),
+        ),
+    ]
diff --git a/aleksis/core/models.py b/aleksis/core/models.py
index 4151d51b39d4cafac8ba91250a5ed64b8d4af50e..07b08f2366402255122721f3fd865f368239731d 100644
--- a/aleksis/core/models.py
+++ b/aleksis/core/models.py
@@ -1773,3 +1773,19 @@ class Holiday(CalendarEvent):
     class Meta:
         verbose_name = _("Holiday")
         verbose_name_plural = _("Holidays")
+
+
+class Organisation(ExtensibleModel):
+    name = models.CharField(verbose_name=_("Name"), max_length=255)
+    email = models.CharField(verbose_name=_("Email"), max_length=255)
+
+    related_group = models.ForeignKey(
+        Group, on_delete=models.CASCADE, verbose_name=_("Related group")
+    )
+
+    def __str__(self) -> str:
+        return f"{self.name}"
+
+    class Meta:
+        verbose_name = _("Organisation")
+        verbose_name_plural = _("Organisations")