diff --git a/arkindex/documents/api/elements.py b/arkindex/documents/api/elements.py
index 7024a304eee36fd9216191c439caf98623c24761..83cb626b504ee295e31ce650ec5588540345d1ca 100644
--- a/arkindex/documents/api/elements.py
+++ b/arkindex/documents/api/elements.py
@@ -28,7 +28,6 @@ from rest_framework.generics import (
     ListAPIView,
     ListCreateAPIView,
     RetrieveUpdateDestroyAPIView,
-    UpdateAPIView,
 )
 from rest_framework.mixins import DestroyModelMixin
 from rest_framework.response import Response
@@ -1445,20 +1444,60 @@ class ElementTypeCreate(CreateAPIView):
 
 
 @extend_schema_view(
-    put=extend_schema(operation_id='UpdateElementType', tags=['elements']),
-    patch=extend_schema(operation_id='PartialUpdateElementType', tags=['elements']),
-)
-class ElementTypeUpdate(UpdateAPIView):
-    """
-    Update an existing element type.
+    get=extend_schema(
+        operation_id='RetrieveElementType',
+        description=dedent("""
+        Retrieve an existing element type.
 
-    This requires admin access to the element type's corpus.
-    """
+        This requires read access to the element type's corpus.
+        """),
+    ),
+    put=extend_schema(
+        operation_id='UpdateElementType',
+        description=dedent("""
+        Update an existing element type.
+
+        This requires admin access to the element type's corpus.
+        """),
+    ),
+    patch=extend_schema(
+        operation_id='PartialUpdateElementType',
+        description=dedent("""
+        Update parts of an existing element type.
+
+        This requires admin access to the element type's corpus.
+        """),
+    ),
+    delete=extend_schema(
+        operation_id='DestroyElementType',
+        description=dedent("""
+        Delete an existing element type if it has no associated elements.
+
+        This requires admin access to the element's type corpus.
+        """)
+    )
+)
+@extend_schema(tags=['elements'])
+class ElementTypeUpdate(RetrieveUpdateDestroyAPIView):
     serializer_class = ElementTypeLightSerializer
     permission_classes = (IsVerifiedOrReadOnly, )
 
     def get_queryset(self):
-        return ElementType.objects.filter(corpus__in=Corpus.objects.admin(self.request.user))
+        if self.request.method in permissions.SAFE_METHODS:
+            corpora = Corpus.objects.readable(self.request.user)
+        else:
+            corpora = Corpus.objects.admin(self.request.user)
+
+        return ElementType.objects.filter(corpus__in=corpora)
+
+    def perform_destroy(self, instance):
+        if instance.elements.exists():
+            raise ValidationError({'detail': ['Some elements are using this element type.']})
+
+        # Update DataImport element type foreign keys manually because letting Django do that can fill up the RAM
+        instance.folder_imports.update(folder_type=None)
+        instance.element_imports.update(element_type=None)
+        super().perform_destroy(instance)
 
 
 @extend_schema_view(
diff --git a/arkindex/documents/tests/test_element_type.py b/arkindex/documents/tests/test_element_type.py
index 8b3e7e1105dd2249b9d3d9472fd17d93d739be34..be7589fe305c2cf21963fe44139e6ca7d9160b65 100644
--- a/arkindex/documents/tests/test_element_type.py
+++ b/arkindex/documents/tests/test_element_type.py
@@ -201,3 +201,30 @@ class TestElementType(FixtureAPITestCase):
                 'folder': self.element_type.folder
             }
         )
+
+    def test_delete_requires_login(self):
+        response = self.client.delete(reverse('api:element-type', kwargs={'pk': self.element_type.id}))
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_delete_requires_admin(self):
+        private_element_type = ElementType.objects.create(corpus=self.private_corpus, slug='element', display_name='Element')
+        self.private_corpus.memberships.create(user=self.user, level=Role.Contributor.value)
+        self.client.force_login(self.user)
+        response = self.client.delete(reverse('api:element-type', kwargs={'pk': private_element_type.id}))
+        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+    def test_delete(self):
+        self.client.force_login(self.superuser)
+        with self.assertNumQueries(11):
+            response = self.client.delete(reverse('api:element-type', kwargs={'pk': self.element_type.id}))
+            self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
+        with self.assertRaises(ElementType.DoesNotExist):
+            self.element_type.refresh_from_db()
+
+    def test_delete_has_elements(self):
+        self.corpus.elements.create(name="can't touch this", type=self.element_type)
+        self.client.force_login(self.superuser)
+        with self.assertNumQueries(4):
+            response = self.client.delete(reverse('api:element-type', kwargs={'pk': self.element_type.id}))
+            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+        self.assertDictEqual(response.json(), {'detail': ['Some elements are using this element type.']})