diff --git a/AUTHORS b/AUTHORS
index 257f8f2c5d..4ac99db75e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -590,6 +590,7 @@ answer newbie questions, and generally made Django that much better:
     Mikhail Korobov <kmike84@googlemail.com>
     Mikko Hellsing <mikko@sorl.net>
     MikoĊ‚aj Siedlarek <mikolaj.siedlarek@gmail.com>
+    milkomeda
     Milton Waddams
     mitakummaa@gmail.com
     mmarshall
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index bc7a28a45d..ff21abbc79 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -1812,7 +1812,7 @@ class ModelAdmin(BaseModelAdmin):
         Hook for customizing the delete process for the delete view and the
         "delete selected" action.
         """
-        return get_deleted_objects(objs, request.user, self.admin_site)
+        return get_deleted_objects(objs, request, self.admin_site)
 
     @csrf_protect_m
     def delete_view(self, request, object_id, extra_context=None):
diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py
index add7faba56..eae09b2238 100644
--- a/django/contrib/admin/utils.py
+++ b/django/contrib/admin/utils.py
@@ -2,7 +2,6 @@ import datetime
 import decimal
 from collections import defaultdict
 
-from django.contrib.auth import get_permission_codename
 from django.core.exceptions import FieldDoesNotExist
 from django.db import models, router
 from django.db.models.constants import LOOKUP_SEP
@@ -117,7 +116,7 @@ def flatten_fieldsets(fieldsets):
     return field_names
 
 
-def get_deleted_objects(objs, user, admin_site):
+def get_deleted_objects(objs, request, admin_site):
     """
     Find all objects related to ``objs`` that should also be deleted. ``objs``
     must be a homogeneous iterable of objects (e.g. a QuerySet).
@@ -136,12 +135,15 @@ def get_deleted_objects(objs, user, admin_site):
     perms_needed = set()
 
     def format_callback(obj):
-        has_admin = obj.__class__ in admin_site._registry
+        model = obj.__class__
+        has_admin = model in admin_site._registry
         opts = obj._meta
 
         no_edit_link = '%s: %s' % (capfirst(opts.verbose_name), obj)
 
         if has_admin:
+            if not admin_site._registry[model].has_delete_permission(request, obj):
+                perms_needed.add(opts.verbose_name)
             try:
                 admin_url = reverse('%s:%s_%s_change'
                                     % (admin_site.name,
@@ -152,10 +154,6 @@ def get_deleted_objects(objs, user, admin_site):
                 # Change url doesn't exist -- don't display link to edit
                 return no_edit_link
 
-            if 'delete' in opts.default_permissions:
-                p = '%s.%s' % (opts.app_label, get_permission_codename('delete', opts))
-                if not user.has_perm(p):
-                    perms_needed.add(opts.verbose_name)
             # Display a link to the admin page.
             return format_html('{}: <a href="{}">{}</a>',
                                capfirst(opts.verbose_name),
diff --git a/tests/modeladmin/tests.py b/tests/modeladmin/tests.py
index 03fd5ef2be..de216cbb11 100644
--- a/tests/modeladmin/tests.py
+++ b/tests/modeladmin/tests.py
@@ -669,13 +669,34 @@ class ModelAdminTests(TestCase):
     def test_get_deleted_objects(self):
         mock_request = MockRequest()
         mock_request.user = User.objects.create_superuser(username='bob', email='bob@test.com', password='test')
-        ma = ModelAdmin(Band, self.site)
+        self.site.register(Band, ModelAdmin)
+        ma = self.site._registry[Band]
         deletable_objects, model_count, perms_needed, protected = ma.get_deleted_objects([self.band], request)
         self.assertEqual(deletable_objects, ['Band: The Doors'])
         self.assertEqual(model_count, {'bands': 1})
         self.assertEqual(perms_needed, set())
         self.assertEqual(protected, [])
 
+    def test_get_deleted_objects_with_custom_has_delete_permission(self):
+        """
+        ModelAdmin.get_deleted_objects() uses ModelAdmin.has_delete_permission()
+        for permissions checking.
+        """
+        mock_request = MockRequest()
+        mock_request.user = User.objects.create_superuser(username='bob', email='bob@test.com', password='test')
+
+        class TestModelAdmin(ModelAdmin):
+            def has_delete_permission(self, request, obj=None):
+                return False
+
+        self.site.register(Band, TestModelAdmin)
+        ma = self.site._registry[Band]
+        deletable_objects, model_count, perms_needed, protected = ma.get_deleted_objects([self.band], request)
+        self.assertEqual(deletable_objects, ['Band: The Doors'])
+        self.assertEqual(model_count, {'bands': 1})
+        self.assertEqual(perms_needed, {'band'})
+        self.assertEqual(protected, [])
+
 
 class ModelAdminPermissionTests(SimpleTestCase):