Index: django/contrib/admin/options.py
===================================================================
--- django/contrib/admin/options.py	(revision 11899)
+++ django/contrib/admin/options.py	(working copy)
@@ -885,10 +885,14 @@
         context.update(extra_context or {})
         return self.render_change_form(request, context, change=True, obj=obj)
 
+    def get_changelist(self, request, **kwargs):
+        from django.contrib.admin.views.main import ChangeList
+        return ChangeList
+
     @csrf_protect
     def changelist_view(self, request, extra_context=None):
         "The 'change list' admin view for this model."
-        from django.contrib.admin.views.main import ChangeList, ERROR_FLAG
+        from django.contrib.admin.views.main import ERROR_FLAG
         opts = self.model._meta
         app_label = opts.app_label
         if not self.has_change_permission(request, None):
@@ -905,8 +909,9 @@
             except ValueError:
                 pass
 
+        changelist = self.get_changelist(request)
         try:
-            cl = ChangeList(request, self.model, list_display, self.list_display_links, self.list_filter,
+            cl = changelist(request, self.model, list_display, self.list_display_links, self.list_filter,
                 self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self.list_editable, self)
         except IncorrectLookupParameters:
             # Wacky lookup parameters were given, so redirect to the main
Index: tests/regressiontests/admin_views/tests.py
===================================================================
--- tests/regressiontests/admin_views/tests.py	(revision 11899)
+++ tests/regressiontests/admin_views/tests.py	(working copy)
@@ -1203,6 +1203,34 @@
         self.failUnlessEqual(Subscriber.objects.count(), 2)
 
 
+class TestCustomChangeList(TestCase):
+    fixtures = ['admin-views-users.xml']
+    
+    urlbit = 'admin'
+    
+    def setUp(self):
+        result = self.client.login(username='super', password='secret')
+        self.failUnlessEqual(result, True)
+
+    def tearDown(self):
+        self.client.logout()
+
+    def test_custom_changelist(self):
+        """
+        Validate that a custom ChangeList class can be used (#9749)
+        """
+        # Insert some data
+        post_data = {"name": u"First Gadget"}
+        response = self.client.post('/test_admin/%s/admin_views/gadget/add/' % self.urlbit, post_data)
+        self.failUnlessEqual(response.status_code, 302) # redirect somewhere
+        # Hit the page once to get messages out of the queue message list
+        response = self.client.get('/test_admin/%s/admin_views/gadget/' % self.urlbit)
+        # Ensure that that data is still not visible on the page
+        response = self.client.get('/test_admin/%s/admin_views/gadget/' % self.urlbit)
+        self.failUnlessEqual(response.status_code, 200)
+        self.assertNotContains(response, 'First Gadget')
+
+
 class TestInlineNotEditable(TestCase):
     fixtures = ['admin-views-users.xml']
 
Index: tests/regressiontests/admin_views/models.py
===================================================================
--- tests/regressiontests/admin_views/models.py	(revision 11899)
+++ tests/regressiontests/admin_views/models.py	(working copy)
@@ -4,6 +4,7 @@
 from django.core.files.storage import FileSystemStorage
 from django.db import models
 from django.contrib import admin
+from django.contrib.admin.views.main import ChangeList
 from django.core.mail import EmailMessage
 
 class Section(models.Model):
@@ -420,6 +421,20 @@
 class CollectorAdmin(admin.ModelAdmin):
     inlines = [WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline, FancyDoodadInline, CategoryInline]
 
+class Gadget(models.Model):
+    name = models.CharField(max_length=100)
+    
+    def __unicode__(self):
+        return self.name
+
+class CustomChangeList(ChangeList):
+    def get_query_set(self):
+        return self.root_query_set.filter(pk=9999) # Does not exist
+
+class GadgetAdmin(admin.ModelAdmin):
+    def get_changelist(self, request, **kwargs):
+        return CustomChangeList
+
 admin.site.register(Article, ArticleAdmin)
 admin.site.register(CustomArticle, CustomArticleAdmin)
 admin.site.register(Section, save_as=True, inlines=[ArticleInline])
@@ -443,6 +458,7 @@
 admin.site.register(Recommender)
 admin.site.register(Collector, CollectorAdmin)
 admin.site.register(Category, CategoryAdmin)
+admin.site.register(Gadget, GadgetAdmin)
 
 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
 # That way we cover all four cases:
