diff --git a/arkindex/documents/api/elements.py b/arkindex/documents/api/elements.py
index 729b0b0915aafbdf6b71ae308b33c5aa8d36fccc..a3852e76c7aab6cf098611f9ae6bccf1a464c96d 100644
--- a/arkindex/documents/api/elements.py
+++ b/arkindex/documents/api/elements.py
@@ -1149,6 +1149,16 @@ class CorpusList(ListCreateAPIView):
         for c in corpora:
             c.access_level = corpora_level[c.id]
 
+            # Avoid making any extra queries to retrieve the top_level_type.
+            # We already have prefetched the types, so we can use corpus.types.all()
+            # when a corpus has a top_level_type_id to retrieve it.
+            if c.top_level_type_id is not None:
+                c.top_level_type = next(
+                    element_type
+                    for element_type in c.types.all()
+                    if element_type.id == c.top_level_type_id
+                )
+
         return corpora
 
 
diff --git a/arkindex/documents/tests/test_corpus.py b/arkindex/documents/tests/test_corpus.py
index 7308792ff597e1f3a318ba87ea5cfa16c12a43aa..273470120d6c99b1722f4f47b09344ca0c887206 100644
--- a/arkindex/documents/tests/test_corpus.py
+++ b/arkindex/documents/tests/test_corpus.py
@@ -69,8 +69,9 @@ class TestCorpus(FixtureAPITestCase):
 
     def test_anon(self):
         # An anonymous user has only access to public
-        response = self.client.get(reverse('api:corpus'))
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        with self.assertNumQueries(4):
+            response = self.client.get(reverse('api:corpus'))
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
 
         self.assertEqual(len(data), 1)
@@ -102,8 +103,9 @@ class TestCorpus(FixtureAPITestCase):
     def test_user(self):
         # A normal user has access to public + its private
         self.client.force_login(self.user)
-        response = self.client.get(reverse('api:corpus'))
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        with self.assertNumQueries(7):
+            response = self.client.get(reverse('api:corpus'))
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
 
         self.assertEqual(len(data), 2)
@@ -150,7 +152,7 @@ class TestCorpus(FixtureAPITestCase):
         self.client.force_login(self.superuser)
         with self.assertNumQueries(5):
             response = self.client.get(reverse('api:corpus'))
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
 
         self.assertEqual(len(data), 3)
@@ -206,6 +208,26 @@ class TestCorpus(FixtureAPITestCase):
             ]
         )
 
+    def test_top_level_type_queries(self):
+        """
+        Multiple corpora with top-level types should only cause one extra SQL query
+        """
+        # Create a bunch of corpora with top-level types
+        for i in range(10):
+            corpus = Corpus.objects.create(name=str(i))
+            element_type = corpus.types.create(slug='top_level')
+            corpus.top_level_type = element_type
+            corpus.save()
+
+        self.client.force_login(self.superuser)
+        with self.assertNumQueries(6):
+            response = self.client.get(reverse('api:corpus'))
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
+        data = response.json()
+
+        self.assertEqual(len(data), 13)
+        self.assertSetEqual({corpus['top_level_type'] for corpus in data}, {None, 'top_level'})
+
     def test_mixin(self):
         vol1 = Element.objects.get(name="Volume 1")
         vol2 = Element.objects.get(name="Volume 2")