diff --git a/src/management/api/course.ts b/src/management/api/course.ts
index e245843..2877959 100644
--- a/src/management/api/course.ts
+++ b/src/management/api/course.ts
@@ -1,11 +1,28 @@
 import { Course } from "@/data";
-import { sampleCourse } from "@/provider/dummy";
 import { axios } from "@/api";
-import { EditionDTO, editionDtoTransformer } from "@/api/dto/edition";
+import { CourseDTO, courseDtoTransformer } from "@/api/dto/course";
+import { encapsulate, OneOrMany } from "@/helpers";
+import { prepare } from "@/routing";
 
-const COURSE_INDEX_ENDPOINT = "/management/course";
+const COURSE_INDEX_ENDPOINT = '/management/course'
+const COURSE_ENDPOINT = COURSE_INDEX_ENDPOINT + "/:id";
 
-export async function all(): Promise<Course[]> {
-    const response = await axios.get<Course[]>(COURSE_INDEX_ENDPOINT);
-    return response.data;
+export async function all(): Promise<Course[]>  {
+    const response = await axios.get<CourseDTO[]>(COURSE_INDEX_ENDPOINT);
+    return response.data.map(dto => courseDtoTransformer.transform(dto))
+}
+
+export async function remove(type: OneOrMany<Course>): Promise<void> {
+    await Promise.all(encapsulate(type).map(
+        type => axios.delete(prepare(COURSE_ENDPOINT, { id: type.id as string }))
+    ));
+}
+
+export async function save(type: Course): Promise<Course> {
+    await axios.put<Course>(
+        COURSE_INDEX_ENDPOINT,
+        courseDtoTransformer.reverseTransform(type)
+    );
+
+    return type;
 }
diff --git a/src/management/api/index.ts b/src/management/api/index.ts
index 2c6309a..ad08c49 100644
--- a/src/management/api/index.ts
+++ b/src/management/api/index.ts
@@ -1,17 +1,17 @@
+import * as course from "./course"
 import * as edition from "./edition"
 import * as page from "./page"
 import * as type from "./type"
-import * as course from "./course"
 import * as internship from "./internship"
 import * as document from "./document"
 import * as field from "./field"
 import * as report from "./report"
 
 export const api = {
+    course,
     edition,
     page,
     type,
-    course,
     internship,
     document,
     field,
diff --git a/src/management/course/edit.tsx b/src/management/course/edit.tsx
new file mode 100644
index 0000000..fb9fbf0
--- /dev/null
+++ b/src/management/course/edit.tsx
@@ -0,0 +1,47 @@
+import { Button, Dialog, DialogActions, DialogContent, DialogProps, DialogTitle } from "@material-ui/core";
+import React from "react";
+import { Form, Formik } from "formik";
+import { initialStaticPageFormValues, StaticPageForm, StaticPageFormValues, staticPageFormValuesTransformer } from "@/management/page/form";
+import { Actions } from "@/components";
+import { Save } from "@material-ui/icons";
+import { useTranslation } from "react-i18next";
+import { Cancel } from "mdi-material-ui";
+import { useSpacing } from "@/styles";
+import { initialCourseFormValues, CourseForm, CourseFormValues, courseFormValuesTransformer } from "@/management/course/form";
+import { Course } from "@/data";
+
+export type EditCourseDialogProps = {
+    onSave?: (page: Course) => void;
+    value?: Course;
+} & DialogProps;
+
+export function EditCourseDialog({ onSave, value, ...props }: EditCourseDialogProps) {
+    const { t } = useTranslation("management");
+    const spacing = useSpacing(3);
+
+    const handleSubmit = (values: CourseFormValues) => {
+        onSave?.(courseFormValuesTransformer.reverseTransform(values));
+    };
+
+    const initialValues = value
+        ? courseFormValuesTransformer.transform(value)
+        : initialCourseFormValues;
+
+    return <Dialog { ...props } maxWidth="lg">
+        <Formik initialValues={ initialValues } onSubmit={ handleSubmit }>
+            <Form className={ spacing.vertical }>
+                <DialogTitle>{ t(value ? "type.edit.title" : "type.create.title") }</DialogTitle>
+                <DialogContent>
+                    <CourseForm />
+                </DialogContent>
+                <DialogActions>
+                    <Actions>
+                        <Button variant="contained" color="primary" startIcon={ <Save /> } type="submit">{ t("save") }</Button>
+                        <Button startIcon={ <Cancel /> } onClick={ ev => props.onClose?.(ev, "escapeKeyDown") }>{ t("cancel") }</Button>
+                    </Actions>
+                </DialogActions>
+            </Form>
+        </Formik>
+    </Dialog>
+}
+
diff --git a/src/management/course/form.tsx b/src/management/course/form.tsx
new file mode 100644
index 0000000..bd82e59
--- /dev/null
+++ b/src/management/course/form.tsx
@@ -0,0 +1,58 @@
+import React from "react";
+import { Course } from "@/data";
+import { Semester } from "@/data/student";
+import { useTranslation } from "react-i18next";
+import { useSpacing } from "@/styles";
+import { Field, FieldProps } from "formik";
+import { TextField as TextFieldFormik } from "formik-material-ui";
+import { Checkbox, Grid } from "@material-ui/core";
+import { identityTransformer, Transformer } from "@/serialization";
+
+export type CourseFormValues = Omit<Course, 'id'>;
+
+export const initialCourseFormValues: CourseFormValues = {
+    name: "",
+    desiredSemesters: []
+}
+
+export const courseFormValuesTransformer: Transformer<Course, CourseFormValues> = identityTransformer;
+
+export const DesiredSemestersField = ({ field, form, meta, ...props }: FieldProps<Semester[]>) => {
+    const { name, value = [] } = field;
+    const { t } = useTranslation("management");
+
+    const toggle = (sid: Semester) => () => {
+        if (!value.includes(sid)) {
+            form.setFieldValue(name, [...value, sid]);
+        } else {
+            form.setFieldValue(name, value.filter((a) => a != sid));
+        }
+    }
+    const isChecked = (sid: Semester) => value.includes(sid);
+
+    const desiredSemesterCheckboxes = [];
+    for (var semesterId = 1; semesterId <= 10; semesterId++) {
+        const sid = semesterId;
+
+        desiredSemesterCheckboxes.push(
+            <Grid item xs={3}>
+                <Checkbox edge="start" onChange={ toggle(sid) } checked={ isChecked(sid) }/>
+                { t("course.field.desiredSemester", {semesterId: semesterId})}
+            </Grid>
+        );
+    }
+
+    return <Grid container spacing={3}>
+        { desiredSemesterCheckboxes }
+    </Grid>
+}
+
+export function CourseForm() {
+    const { t } = useTranslation("management");
+    const spacing = useSpacing(2);
+
+    return <div className={ spacing.vertical }>
+        <Field label={ t("page.field.title") } name="name" fullWidth component={ TextFieldFormik }/>
+        <Field name="desiredSemesters" component={ DesiredSemestersField } />
+    </div>
+}
diff --git a/src/management/course/list.tsx b/src/management/course/list.tsx
new file mode 100644
index 0000000..2b572f3
--- /dev/null
+++ b/src/management/course/list.tsx
@@ -0,0 +1,139 @@
+import { Page } from "@/pages/base";
+import React, { useEffect, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { useAsyncState } from "@/hooks";
+import { Course } from "@/data";
+import api from "@/management/api";
+import { Management } from "@/management/main";
+import { Button, Container, IconButton, Tooltip, Typography } from "@material-ui/core";
+import { Async } from "@/components/async";
+import MaterialTable, { Column } from "material-table";
+import { MaterialTableTitle } from "@/management/common/MaterialTableTitle";
+import { actionsColumn, fieldComparator, multilingualStringComparator } from "@/management/common/helpers";
+import { AccountCheck, Delete, Refresh, ShieldCheck } from "mdi-material-ui";
+import { OneOrMany } from "@/helpers";
+import { createDeleteAction } from "@/management/common/DeleteResourceAction";
+import { BulkActions } from "@/management/common/BulkActions";
+import { useSpacing } from "@/styles";
+import { Actions } from "@/components";
+import { MultilingualCell } from "@/management/common/MultilangualCell";
+import { default as StaticPage } from "@/data/page";
+import { Add, Edit } from "@material-ui/icons";
+import { createPortal } from "react-dom";
+import { EditStaticPageDialog } from "@/management/page/edit";
+import { EditCourseDialog } from "@/management/course/edit";
+
+const title = "course.index.title";
+
+const label = (course: Course) => course?.name;
+
+export const CourseManagement = () => {
+    const { t } = useTranslation("management");
+    const [result, setCoursesPromise] = useAsyncState<Course[]>();
+    const [selected, setSelected] = useState<Course[]>([]);
+    const spacing = useSpacing(2);
+
+    const updateCourseList = () => {
+        setCoursesPromise(api.course.all());
+    }
+
+    const handleCourseDelete = async (type: OneOrMany<Course>) => {
+        await api.course.remove(type);
+        updateCourseList();
+    }
+
+    useEffect(updateCourseList, []);
+
+    const DeleteCourseAction = createDeleteAction({ label, onDelete: handleCourseDelete });
+
+    const CreateCourseAction = () => {
+        const [ open, setOpen ] = useState<boolean>(false);
+
+        const handleCourseCreation = async (value: Course) => {
+            await api.course.save(value);
+            setOpen(false);
+            updateCourseList();
+        }
+
+        return <>
+            <Button variant="contained" color="primary" startIcon={ <Add /> } onClick={ () => setOpen(true) }>{ t("create") }</Button>
+            { open && createPortal(
+                <EditCourseDialog open={ open } onSave={ handleCourseCreation } onClose={ () => setOpen(false) }/>,
+                document.getElementById("modals") as Element
+            ) }
+        </>
+    }
+
+    const EditCourseAction = ({ resource }: { resource: Course }) => {
+        const [ open, setOpen ] = useState<boolean>(false);
+
+        const handleCourseCreation = async (value: Course) => {
+            await api.course.save(value);
+            setOpen(false);
+            updateCourseList();
+        }
+
+        return <>
+            <Tooltip title={ t("actions.edit") as any }>
+                <IconButton onClick={ () => setOpen(true) }><Edit /></IconButton>
+            </Tooltip>
+            { open && createPortal(
+                <EditCourseDialog open={ open } onSave={ handleCourseCreation } value={ resource } onClose={ () => setOpen(false) }/>,
+                document.getElementById("modals") as Element
+            ) }
+        </>
+    }
+
+    const columns: Column<Course>[] = [
+        {
+            field: "id",
+            title: "ID",
+            width: 0,
+            defaultSort: "asc",
+            filtering: false,
+        },
+        {
+            title: t("course.field.name"),
+            render: type => type.name,
+            customSort: (a, b) => a.name.localeCompare(b.name),
+        },
+        {
+            title: t("course.field.desiredSemesters"),
+            render: type => type.desiredSemesters.slice().sort().join(", "),
+            sorting: false
+        },
+        actionsColumn(type => <>
+            <DeleteCourseAction resource={ type }/>
+            <EditCourseAction resource={ type }/>
+        </>)
+    ];
+
+    return <Page>
+        <Page.Header maxWidth="lg">
+            <Management.Breadcrumbs>
+                <Typography color="textPrimary">{ t(title) }</Typography>
+            </Management.Breadcrumbs>
+            <Page.Title>{ t(title) }</Page.Title>
+        </Page.Header>
+        <Container maxWidth="lg" className={ spacing.vertical }>
+            <Actions>
+                <CreateCourseAction />
+                <Button onClick={ updateCourseList } startIcon={ <Refresh /> }>{ t("refresh") }</Button>
+            </Actions>
+            { selected.length > 0 && <BulkActions>
+                <DeleteCourseAction resource={ selected }>
+                    { action => <Button startIcon={ <Delete /> } onClick={ action }>{ t("actions.delete") }</Button> }
+                </DeleteCourseAction>
+            </BulkActions> }
+            <Async async={ result } keepValue>{
+                pages => <MaterialTable
+                    title={ <MaterialTableTitle result={ result } label={ t(title) }/> }
+                    columns={ columns }
+                    data={ pages }
+                    onSelectionChange={ pages => setSelected(pages) }
+                    options={ { selection: true, pageSize: 10 } }
+                />
+            }</Async>
+        </Container>
+    </Page>
+}
diff --git a/src/management/main.tsx b/src/management/main.tsx
index ba98c8f..d46e065 100644
--- a/src/management/main.tsx
+++ b/src/management/main.tsx
@@ -4,7 +4,7 @@ import React from "react";
 import { Link as RouterLink } from "react-router-dom";
 import { route } from "@/routing";
 import { useTranslation } from "react-i18next";
-import { CalendarClock, FileCertificateOutline, FileDocumentMultipleOutline, FormatPageBreak } from "mdi-material-ui";
+import { CalendarClock, FileCertificateOutline, FileDocumentMultipleOutline, FormatPageBreak, TableOfContents } from "mdi-material-ui";
 
 export const ManagementLink = ({ icon, route, children }: ManagementLinkProps) =>
     <ListItem button component={ RouterLink } to={ route }>
@@ -40,6 +40,9 @@ export const ManagementIndex = () => {
         <Container>
             <Paper elevation={ 2 }>
                 <Management.Menu>
+                    <ManagementLink icon={ <TableOfContents /> } route={ route("management:courses") }>
+                        { t("management:course.index.title") }
+                    </ManagementLink>
                     <ManagementLink icon={ <CalendarClock /> } route={ route("management:editions") }>
                         { t("management:edition.index.title") }
                     </ManagementLink>
diff --git a/src/management/routing.tsx b/src/management/routing.tsx
index efdf24a..052e971 100644
--- a/src/management/routing.tsx
+++ b/src/management/routing.tsx
@@ -1,5 +1,6 @@
 import { Route } from "@/routing";
 import { isManagerMiddleware } from "@/management/middleware";
+import { CourseManagement } from "@/management/course/list";
 import { EditionsManagement } from "@/management/edition/list";
 import React from "react";
 import { ManagementIndex } from "@/management/main";
@@ -17,6 +18,7 @@ import { EditionReportSchema } from "@/management/edition/report-schema";
 export const managementRoutes: Route[] = ([
     { name: "index", path: "/", content: ManagementIndex, exact: true },
 
+    { name: "courses", path: "/courses", content: CourseManagement },
     { name: "edition_router", path: "/editions/:edition", content: EditionRouter },
     { name: "edition_settings", path: "/editions/:edition/settings", content: EditionSettings, tags: ["edition"] },
     { name: "edition_manage", path: "/editions/:edition", content: EditionManagement, tags: ["edition"], exact: true },