diff --git a/aleksis/apps/alsijil/migrations/0002_excuse_type.py b/aleksis/apps/alsijil/migrations/0002_excuse_type.py
new file mode 100644
index 0000000000000000000000000000000000000000..0652bd19fac38b1743aef574f75e604f622609e9
--- /dev/null
+++ b/aleksis/apps/alsijil/migrations/0002_excuse_type.py
@@ -0,0 +1,40 @@
+# Generated by Django 3.0.8 on 2020-07-10 10:46
+
+import django.contrib.postgres.fields.jsonb
+import django.contrib.sites.managers
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('sites', '0002_alter_domain_unique'),
+        ('alsijil', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ExcuseType',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
+                ('short_name', models.CharField(max_length=255, unique=True, verbose_name='Short name')),
+                ('name', models.CharField(max_length=255, unique=True, verbose_name='Name')),
+                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
+            ],
+            options={
+                'verbose_name': 'Excuse type',
+                'verbose_name_plural': 'Excuse types',
+                'ordering': ['name'],
+            },
+            managers=[
+                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
+            ],
+        ),
+        migrations.AddField(
+            model_name='personalnote',
+            name='excuse_type',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='alsijil.ExcuseType', verbose_name='Excuse type'),
+        ),
+    ]
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index eb1bc4eb67f37744e589c8daf9d496ff6913f6d3..296c3375d96f3edc7fd7b64aa927b725888e0fe5 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -8,6 +8,21 @@ def isidentifier(value: str) -> bool:
     return value.isidentifier()
 
 
+class ExcuseType(ExtensibleModel):
+    """An type of excuse.
+
+    Can be used to count different types of absences separately.
+    """
+
+    short_name = models.CharField(max_length=255, unique=True, verbose_name=_("Short name"))
+    name = models.CharField(max_length=255, unique=True, verbose_name=_("Name"))
+
+    class Meta:
+        ordering = ["name"]
+        verbose_name = _("Excuse type")
+        verbose_name_plural = _("Excuse types")
+
+
 class PersonalNote(ExtensibleModel):
     """A personal note about a single person.
 
@@ -27,6 +42,7 @@ class PersonalNote(ExtensibleModel):
     absent = models.BooleanField(default=False)
     late = models.IntegerField(default=0)
     excused = models.BooleanField(default=False)
+    excuse_type = models.ForeignKey(ExcuseType, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Excuse type"))
 
     remarks = models.CharField(max_length=200, blank=True)