diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index ff21abbc79..62c881eb74 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -1574,7 +1574,7 @@ class ModelAdmin(BaseModelAdmin):
                 form = ModelForm(instance=obj)
                 formsets, inline_instances = self._create_formsets(request, obj, change=True)
 
-        if not add and not self.has_change_permission(request):
+        if not add and not self.has_change_permission(request, obj):
             readonly_fields = flatten_fieldsets(self.get_fieldsets(request, obj))
         else:
             readonly_fields = self.get_readonly_fields(request, obj)
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index 51791e961e..ad29e6ea14 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -1116,3 +1116,13 @@ site6.register(Article, ArticleAdmin6)
 site6.register(Actor, ActorAdmin6)
 site6.register(Chapter, ChapterAdmin6)
 site6.register(Color, ColorAdmin6)
+
+
+class ArticleAdmin9(admin.ModelAdmin):
+    def has_change_permission(self, request, obj=None):
+        # Simulate that the user can't change a specific object.
+        return obj is None
+
+
+site9 = admin.AdminSite(name='admin9')
+site9.register(Article, ArticleAdmin9)
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 95fa487c5f..e64ee9b6a3 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -1852,6 +1852,18 @@ class AdminViewPermissionsTest(TestCase):
             self.assertContains(response, 'login-form')
             self.client.get(reverse('admin:logout'))
 
+    def test_change_view_without_object_change_permission(self):
+        """
+        The object should be read-only if the user has permission to view it
+        and change objects of that type but not to change the current object.
+        """
+        change_url = reverse('admin9:admin_views_article_change', args=(self.a1.pk,))
+        self.client.force_login(self.viewuser)
+        response = self.client.get(change_url)
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.context['title'], 'View article')
+        self.assertContains(response, '<a href="/test_admin/admin9/admin_views/article/" class="closelink">Close</a>')
+
     def test_change_view_save_as_new(self):
         """
         'Save as new' should raise PermissionDenied for users without the 'add'
diff --git a/tests/admin_views/urls.py b/tests/admin_views/urls.py
index c2d989b245..d02875cf56 100644
--- a/tests/admin_views/urls.py
+++ b/tests/admin_views/urls.py
@@ -16,6 +16,7 @@ urlpatterns = [
     url(r'^test_admin/admin7/', admin.site7.urls),
     # All admin views accept `extra_context` to allow adding it like this:
     url(r'^test_admin/admin8/', (admin.site.get_urls(), 'admin', 'admin-extra-context'), {'extra_context': {}}),
+    url(r'^test_admin/admin9/', admin.site9.urls),
     url(r'^test_admin/has_permission_admin/', custom_has_permission_admin.site.urls),
     url(r'^test_admin/autocomplete_admin/', autocomplete_site.urls),
 ]