diff --git a/app/controllers/course/topics.php b/app/controllers/course/topics.php
index d90955f9b2b757b3f88a3a7a6b98200129f71b49..dc752760fb71149e3226d7a59d8e6be8e39fb727 100644
--- a/app/controllers/course/topics.php
+++ b/app/controllers/course/topics.php
@@ -31,6 +31,7 @@ class Course_TopicsController extends AuthenticatedController
     public function index_action()
     {
         $this->topics = CourseTopic::findBySeminar_id(Context::getId());
+        $this->topic_links = $this->createLinksForTopics($this->topics);
         $this->cancelled_dates_locked = LockRules::Check(Context::getId(), 'cancelled_dates');
     }
 
@@ -107,26 +108,25 @@ class Course_TopicsController extends AuthenticatedController
         $this->redirect($this->indexURL(['open' => $topic->id]));
     }
 
-    public function move_up_action(CourseTopic $topic)
+    public function swap_action(CourseTopic $a, CourseTopic $b)
     {
         if (!Request::isPost()) {
             throw new MethodNotAllowedException();
         }
 
-        $topic->increasePriority();
-
-        $this->redirect($this->indexURL(['open' => $topic->id]));
-    }
-
-    public function move_down_action(CourseTopic $topic)
-    {
-        if (!Request::isPost()) {
-            throw new MethodNotAllowedException();
+        if (
+            $a->seminar_id !== Context::getId()
+            || $b->seminar_id !== Context::getId()
+        ) {
+            throw new Exception(_('Eines oder mehrere Themen gehören nicht zur ausgewählten Veranstaltung.'));
         }
 
-        $topic->decreasePriority();
+        [$a->priority, $b->priority] = [$b->priority, $a->priority];
 
-        $this->redirect($this->indexURL(['open' => $topic->id]));
+        $a->store();
+        $b->store();
+
+        $this->redirect($this->indexURL(['open' => $a->id]));
     }
 
     public function allow_public_action()
@@ -263,4 +263,30 @@ class Course_TopicsController extends AuthenticatedController
             );
         }
     }
+
+    private function createLinksForTopics(array $topics): array
+    {
+        $links = array_combine(
+            array_column($topics, 'id'),
+            array_fill(0, count($topics), ['previous' => null, 'next' => null])
+        );
+
+        $last = null;
+        foreach ($topics as $topic) {
+            if ($last !== null) {
+                $links[$topic->id]['previous'] = $last;
+            }
+            $last = $topic;
+        }
+
+        $next = null;
+        foreach (array_reverse($topics) as $topic) {
+            if ($next !== null) {
+                $links[$topic->id]['next'] = $next;
+            }
+            $next = $topic;
+        }
+
+        return $links;
+    }
 }
diff --git a/app/views/course/topics/index.php b/app/views/course/topics/index.php
index b0f5f48aadb1e924fdf9c0adf5ebe1032f614747..452f7bd9cb929212732eadaf214ccafa439a2c02 100644
--- a/app/views/course/topics/index.php
+++ b/app/views/course/topics/index.php
@@ -1,3 +1,10 @@
+<?php
+/**
+ * @var CourseTopic[] $topics
+ * @var Course_TopicsController $controller
+ * @var array<array{next: ?CourseTopic, previous: ?CourseTopic}> $topic_links
+ */
+?>
 <? if (count($topics) > 0) : ?>
 <table class="default withdetails">
     <colgroup>
@@ -102,13 +109,13 @@
                             <? endif ?>
 
                             <span class="button-group">
-                            <? if ($key > 0) : ?>
-                                <form action="<?= $controller->move_up($topic) ?>" method="post" style="display: inline;">
+                            <? if ($topic_links[$topic->id]['previous']) : ?>
+                                <form action="<?= $controller->swap($topic, $topic_links[$topic->id]['previous']) ?>" method="post" style="display: inline;">
                                     <?= Studip\Button::createMoveUp(_('nach oben verschieben')) ?>
                                 </form>
                             <? endif ?>
-                            <? if ($key < count($topics) - 1) : ?>
-                                <form action="<?=$controller->move_down($topic)?>" method="post" style="display: inline;">
+                            <? if ($topic_links[$topic->id]['next']) : ?>
+                                <form action="<?= $controller->swap($topic, $topic_links[$topic->id]['next']) ?>" method="post" style="display: inline;">
                                     <?= Studip\Button::createMoveDown(_('nach unten verschieben')) ?>
                                 </form>
                             <? endif ?>
diff --git a/lib/models/CourseTopic.class.php b/lib/models/CourseTopic.class.php
index 56a060d16df369aced98064e050d9e0b144fb03b..61468d700db2178e494706a66d8c251e0027d342 100644
--- a/lib/models/CourseTopic.class.php
+++ b/lib/models/CourseTopic.class.php
@@ -197,6 +197,7 @@ class CourseTopic extends SimpleORMap
      * mean higher priority.
      *
      * @return boolean
+     * @todo Deprecated, remove for Stud.IP 6.0
      */
     public function increasePriority()
     {
@@ -227,6 +228,8 @@ class CourseTopic extends SimpleORMap
      * Decreases the priority of this topic. Meaning the topic will be sorted further down.
      * Be aware that this actually increases the priority property since higher numbers
      * mean lower priority.
+     *
+     * @todo Deprecated, remove for Stud.IP 6.0
      */
     public function decreasePriority()
     {