diff --git a/aleksis/apps/alsijil/forms.py b/aleksis/apps/alsijil/forms.py
index 3d7f554eb2750784c3217eeaff4c09baae330520..7def50627f0a113ba6738440a36634a027c5a7b4 100644
--- a/aleksis/apps/alsijil/forms.py
+++ b/aleksis/apps/alsijil/forms.py
@@ -11,7 +11,7 @@ from material import Layout, Row
 from aleksis.apps.chronos.managers import TimetableType
 from aleksis.core.models import Group, Person
 
-from .models import LessonDocumentation, PersonalNote, PersonalNoteFilter
+from .models import ExtraMark, LessonDocumentation, PersonalNote, PersonalNoteFilter
 
 
 class LessonDocumentationForm(forms.ModelForm):
@@ -116,3 +116,11 @@ class PersonalNoteFilterForm(forms.ModelForm):
     class Meta:
         model = PersonalNoteFilter
         fields = ["identifier", "description", "regex"]
+
+
+class ExtraMarkForm(forms.ModelForm):
+    layout = Layout("short_name", "name")
+
+    class Meta:
+        model = ExtraMark
+        fields = ["short_name", "name"]
diff --git a/aleksis/apps/alsijil/menus.py b/aleksis/apps/alsijil/menus.py
index 2b84cb6f7f70b644a34f79f170dfc4cb6751f773..e18a62352ebe850649baec923d4857734b6b89c9 100644
--- a/aleksis/apps/alsijil/menus.py
+++ b/aleksis/apps/alsijil/menus.py
@@ -36,6 +36,12 @@ MENUS = {
                     "icon": "filter_list",
                     "validators": ["menu_generator.validators.is_superuser"],
                 },
+                {
+                    "name": _("Extra marks"),
+                    "url": "extra_marks",
+                    "icon": "label",
+                    "validators": ["menu_generator.validators.is_superuser"],
+                },
             ],
         }
     ]
diff --git a/aleksis/apps/alsijil/tables.py b/aleksis/apps/alsijil/tables.py
index bad0dc9f3923421035d0701251012461df13fec8..c3b393b61d8b513157c7984940624394c9e8026f 100644
--- a/aleksis/apps/alsijil/tables.py
+++ b/aleksis/apps/alsijil/tables.py
@@ -17,3 +17,23 @@ class PersonalNoteFilterTable(tables.Table):
         text=_("Edit"),
         attrs={"a": {"class": "btn-flat waves-effect waves-orange"}},
     )
+
+
+class ExtraMarkTable(tables.Table):
+    class Meta:
+        attrs = {"class": "highlight"}
+
+    name = tables.LinkColumn("edit_extra_mark", args=[A("id")])
+    short_name = tables.Column()
+    edit = tables.LinkColumn(
+        "edit_extra_mark",
+        args=[A("id")],
+        text=_("Edit"),
+        attrs={"a": {"class": "btn-flat waves-effect waves-orange orange-text"}},
+    )
+    delete = tables.LinkColumn(
+        "delete_extra_mark",
+        args=[A("id")],
+        text=_("Delete"),
+        attrs={"a": {"class": "btn-flat waves-effect waves-red red-text"}},
+    )
diff --git a/aleksis/apps/alsijil/templates/alsijil/extra_mark/create.html b/aleksis/apps/alsijil/templates/alsijil/extra_mark/create.html
new file mode 100644
index 0000000000000000000000000000000000000000..d0ee3a9055561df1f468692f79d794404a60c1d1
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/extra_mark/create.html
@@ -0,0 +1,17 @@
+	{# -*- engine:django -*- #}
+
+	{% extends "core/base.html" %}
+	{% load material_form i18n %}
+
+	{% block browser_title %}{% blocktrans %}Create extra mark{% endblocktrans %}{% endblock %}
+	{% block page_title %}{% blocktrans %}Create extra mark{% endblocktrans %}{% endblock %}
+
+	{% block content %}
+
+	  <form method="post">
+	    {% csrf_token %}
+	    {% form form=form %}{% endform %}
+	    {% include "core/partials/save_button.html" %}
+	  </form>
+
+	{% endblock %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/extra_mark/edit.html b/aleksis/apps/alsijil/templates/alsijil/extra_mark/edit.html
new file mode 100644
index 0000000000000000000000000000000000000000..7adee30a1cfd30256d70b2a823827384de331e05
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/extra_mark/edit.html
@@ -0,0 +1,17 @@
+{# -*- engine:django -*- #}
+
+{% extends "core/base.html" %}
+{% load material_form i18n %}
+
+{% block browser_title %}{% blocktrans %}Edit extra mark{% endblocktrans %}{% endblock %}
+{% block page_title %}{% blocktrans %}Edit extra mark{% endblocktrans %}{% endblock %}
+
+{% block content %}
+
+  <form method="post">
+    {% csrf_token %}
+    {% form form=form %}{% endform %}
+    {% include "core/partials/save_button.html" %}
+  </form>
+
+{% endblock %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/extra_mark/list.html b/aleksis/apps/alsijil/templates/alsijil/extra_mark/list.html
new file mode 100644
index 0000000000000000000000000000000000000000..a1a12b38096de60bae34d61425a1da9c688ab9d6
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/extra_mark/list.html
@@ -0,0 +1,18 @@
+{# -*- engine:django -*- #}
+
+{% extends "core/base.html" %}
+
+{% load i18n %}
+{% load render_table from django_tables2 %}
+
+{% block browser_title %}{% blocktrans %}Extra marks{% endblocktrans %}{% endblock %}
+{% block page_title %}{% blocktrans %}Extra marks{% endblocktrans %}{% endblock %}
+
+{% block content %}
+  <a class="btn green waves-effect waves-light" href="{% url 'create_extra_mark' %}">
+    <i class="material-icons left">add</i>
+    {% trans "Create extra mark" %}
+  </a>
+
+  {% render_table table %}
+{% endblock %}
diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py
index 4406a06852ae2489eaf5b84c66a28098d91f0010..7f022fbb127ecfe523da6840041b7b75f043f849 100644
--- a/aleksis/apps/alsijil/urls.py
+++ b/aleksis/apps/alsijil/urls.py
@@ -41,4 +41,20 @@ urlpatterns = [
         views.delete_personal_note_filter,
         name="delete_personal_note_filter",
     ),
+    path("extra_marks/", views.ExtraMarkListView.as_view(), name="extra_marks"),
+    path(
+        "extra_marks/create/",
+        views.ExtraMarkCreateView.as_view(),
+        name="create_extra_mark",
+    ),
+    path(
+        "extra_marks/<int:pk>/edit/",
+        views.ExtraMarkEditView.as_view(),
+        name="edit_extra_mark",
+    ),
+    path(
+        "extra_marks/<int:pk>/delete/",
+        views.ExtraMarkDeleteView.as_view(),
+        name="delete_extra_mark",
+    ),
 ]
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index 999cbffec3ea1cacc8c2e08daa11d9da2039c16a..17f2b75ec7f01d0d0acd1f1f33557ed9fb5c02db 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -5,27 +5,31 @@ from django.core.exceptions import PermissionDenied
 from django.db.models import Count, Exists, F, OuterRef, Q, Subquery, Sum
 from django.http import Http404, HttpRequest, HttpResponse, HttpResponseNotFound
 from django.shortcuts import get_object_or_404, redirect, render
-from django.urls import reverse
+from django.urls import reverse, reverse_lazy
 from django.utils.translation import ugettext as _
 
 from calendarweek import CalendarWeek
-from django_tables2 import RequestConfig
+from django_tables2 import RequestConfig, SingleTableView
+from reversion.views import RevisionMixin
+from rules.contrib.views import PermissionRequiredMixin
 
 from aleksis.apps.chronos.managers import TimetableType
 from aleksis.apps.chronos.models import LessonPeriod
 from aleksis.apps.chronos.util.chronos_helpers import get_el_by_pk
+from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView
 from aleksis.core.models import Group, Person, SchoolTerm
 from aleksis.core.util import messages
 
 from .forms import (
+    ExtraMarkForm,
     LessonDocumentationForm,
     PersonalNoteFilterForm,
     PersonalNoteFormSet,
     RegisterAbsenceForm,
     SelectForm,
 )
-from .models import LessonDocumentation, PersonalNoteFilter
-from .tables import PersonalNoteFilterTable
+from .models import ExtraMark, LessonDocumentation, PersonalNoteFilter
+from .tables import ExtraMarkTable, PersonalNoteFilterTable
 
 
 def lesson(
@@ -418,3 +422,44 @@ def delete_personal_note_filter(request: HttpRequest, id_: int) -> HttpResponse:
 
     context["personal_note_filter"] = personal_note_filter
     return redirect("list_personal_note_filters")
+
+
+class ExtraMarkListView(SingleTableView, PermissionRequiredMixin):
+    """Table of all extra marks."""
+
+    model = ExtraMark
+    table_class = ExtraMarkTable
+    permission_required = "core.view_extramark"
+    template_name = "alsijil/extra_mark/list.html"
+
+
+class ExtraMarkCreateView(AdvancedCreateView, PermissionRequiredMixin):
+    """Create view for extra marks."""
+
+    model = ExtraMark
+    form_class = ExtraMarkForm
+    permission_required = "core.create_extramark"
+    template_name = "alsijil/extra_mark/create.html"
+    success_url = reverse_lazy("extra_marks")
+    success_message = _("The extra mark has been created.")
+
+
+class ExtraMarkEditView(AdvancedEditView, PermissionRequiredMixin):
+    """Edit view for extra marks."""
+
+    model = ExtraMark
+    form_class = ExtraMarkForm
+    permission_required = "core.edit_extramark"
+    template_name = "alsijil/extra_mark/edit.html"
+    success_url = reverse_lazy("extra_marks")
+    success_message = _("The extra mark has been saved.")
+
+
+class ExtraMarkDeleteView(AdvancedDeleteView, PermissionRequiredMixin, RevisionMixin):
+    """Delete view for extra marks"""
+
+    model = ExtraMark
+    permission_required = "core.delete_extramark"
+    template_name = "core/pages/delete.html"
+    success_url = reverse_lazy("extra_marks")
+    success_message = _("The extra mark has been deleted.")