diff --git a/django/test/client.py b/django/test/client.py
--- a/django/test/client.py
+++ b/django/test/client.py
@@ -13,6 +13,7 @@
 
 from django.conf import settings
 from django.contrib.auth import authenticate, login
+from django.contrib.sessions.middleware import SessionMiddleware
 from django.core.handlers.base import BaseHandler
 from django.core.handlers.wsgi import WSGIRequest
 from django.core.signals import got_request_exception
@@ -24,6 +25,7 @@
 from django.utils.http import urlencode
 from django.utils.importlib import import_module
 from django.utils.itercompat import is_iterable
+from django.utils.module_loading import issubclass_by_name
 from django.db import close_connection
 from django.test.utils import ContextList
 
@@ -497,8 +499,13 @@
         not available.
         """
         user = authenticate(**credentials)
-        if user and user.is_active \
-                and 'django.contrib.sessions.middleware.SessionMiddleware' in settings.MIDDLEWARE_CLASSES:
+        sessions_enabled = False
+        if user and user.is_active:
+            for middleware in settings.MIDDLEWARE_CLASSES:
+                sessions_enabled = issubclass_by_name(middleware, SessionMiddleware)
+                if sessions_enabled:
+                    break
+        if sessions_enabled:
             engine = import_module(settings.SESSION_ENGINE)
 
             # Create a fake request to store login details.
diff --git a/django/utils/module_loading.py b/django/utils/module_loading.py
--- a/django/utils/module_loading.py
+++ b/django/utils/module_loading.py
@@ -2,6 +2,8 @@
 import os
 import sys
 
+from django.utils.importlib import import_module
+
 
 def module_has_submodule(package, module_name):
     """See if 'module' is in 'package'."""
@@ -67,3 +69,23 @@
     else:
         # Exhausted the search, so the module cannot be found.
         return False
+
+def issubclass_by_name(symbol_name, klass):
+    """
+    Verify if possibly dotted, in string form :param symbol_name: is a
+    subclass of :param klass:.
+
+    Example:
+
+    >>> issubclass_by_name('django.utils.datastructures.SortedDict', dict)
+    True
+    """
+    try:
+        mod, dot, klass_name = symbol_name.rpartition('.')
+        mod = import_module(mod)
+        subclass = getattr(mod, klass_name, None)
+        if subclass is None:
+            return False
+        return issubclass(subclass, klass)
+    except ImportError:
+        return False
diff --git a/tests/regressiontests/test_client_regress/middleware.py b/tests/regressiontests/test_client_regress/middleware.py
new file mode 100644
--- /dev/null
+++ b/tests/regressiontests/test_client_regress/middleware.py
@@ -0,0 +1,9 @@
+from django.contrib.sessions.middleware import SessionMiddleware
+
+
+class CustomizedDjangoSessionMiddleware(SessionMiddleware):
+    pass
+
+
+class ReallyCustomSessionMiddleware(object):
+    pass
diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py
--- a/tests/regressiontests/test_client_regress/models.py
+++ b/tests/regressiontests/test_client_regress/models.py
@@ -2,6 +2,8 @@
 """
 Regression tests for the Test Client, especially the customized assertions.
 """
+from __future__ import absolute_import
+
 import os
 import warnings
 
@@ -17,6 +19,10 @@
 from django.template.response import SimpleTemplateResponse
 from django.http import HttpResponse
 
+from . import middleware
+
+CUSTOM_SESSION_MIDDLEWARE1 = '%s.CustomizedDjangoSessionMiddleware' % middleware.__name__
+CUSTOM_SESSION_MIDDLEWARE2 = '%s.ReallyCustomSessionMiddleware' % middleware.__name__
 
 class AssertContainsTests(TestCase):
     def setUp(self):
@@ -564,17 +570,42 @@
         self.assertEqual(response.context['user'].username, 'testclient')
 
 
-class NoSessionsAppInstalled(SessionEngineTests):
-    """#7836 - Test client can exercise sessions even when 'django.contrib.sessions' isn't installed."""
+class SessionMiddlewareTests(TestCase):
+    fixtures = ['testdata']
 
     # Remove the 'session' contrib app from INSTALLED_APPS
     @override_settings(INSTALLED_APPS=tuple(filter(lambda a: a!='django.contrib.sessions', settings.INSTALLED_APPS)))
-    def test_session(self):
+    def test_no_session_app(self):
+        """Test client can exercise sessions even when 'django.contrib.sessions' isn't installed (#7836)."""
         # This request sets a session variable.
         response = self.client.get('/test_client_regress/set_session/')
         self.assertEqual(response.status_code, 200)
         self.assertEqual(self.client.session['session_var'], 'YES')
 
+    # Use a custom session middleware that inherits from Django's
+    @override_settings(
+        MIDDLEWARE_CLASSES=map(
+            lambda m: m if m!='django.contrib.sessions.middleware.SessionMiddleware' else CUSTOM_SESSION_MIDDLEWARE1,
+            settings.MIDDLEWARE_CLASSES
+        )
+    )
+    def test_subclassed_session_middleware(self):
+        """Test client can login when a subclass of Django SessionMiddleware is in use (#16605)."""
+        login = self.client.login(username='testclient', password='password')
+        self.assertTrue(login, 'Could not log in')
+
+    # Use a custom session middleware
+    @override_settings(
+        MIDDLEWARE_CLASSES=map(
+            lambda m: m if m!='django.contrib.sessions.middleware.SessionMiddleware' else CUSTOM_SESSION_MIDDLEWARE2,
+            settings.MIDDLEWARE_CLASSES
+        )
+    )
+    def test_custom_session_middleware(self):
+        """Test client can login when a custom session middleware is in use."""
+        login = self.client.login(username='testclient', password='password')
+        self.assertTrue(login, 'Could not log in')
+
 
 class URLEscapingTests(TestCase):
     def test_simple_argument_get(self):
diff --git a/tests/regressiontests/utils/module_loading.py b/tests/regressiontests/utils/module_loading.py
--- a/tests/regressiontests/utils/module_loading.py
+++ b/tests/regressiontests/utils/module_loading.py
@@ -5,7 +5,7 @@
 
 from django.utils import unittest
 from django.utils.importlib import import_module
-from django.utils.module_loading import module_has_submodule
+from django.utils.module_loading import module_has_submodule, issubclass_by_name
 
 
 class DefaultLoader(unittest.TestCase):
@@ -154,3 +154,17 @@
     def tearDown(self):
         super(CustomLoader, self).tearDown()
         sys.path_hooks.pop(0)
+
+
+class IssubclassByNameTests(unittest.TestCase):
+    def test_success(self):
+        self.assertTrue(issubclass_by_name('django.utils.datastructures.SortedDict', dict))
+
+    def test_failure(self):
+        self.assertFalse(issubclass_by_name('django.utils.datastructures.SortedDict', str))
+
+    def test_import_failure_returns_false(self):
+        self.assertFalse(issubclass_by_name('i.dont.exist.SortedDict', str))
+
+    def test_bogus_symbol_name_returns_false(self):
+        self.assertFalse(issubclass_by_name('django.utils.module_loading.IDontExist', str))
diff --git a/tests/regressiontests/utils/tests.py b/tests/regressiontests/utils/tests.py
--- a/tests/regressiontests/utils/tests.py
+++ b/tests/regressiontests/utils/tests.py
@@ -5,7 +5,7 @@
 
 from .dateformat import DateFormatTests
 from .feedgenerator import FeedgeneratorTest
-from .module_loading import DefaultLoader, EggLoader, CustomLoader
+from .module_loading import DefaultLoader, EggLoader, CustomLoader, IssubclassByNameTests
 from .termcolors import TermColorTests
 from .html import TestUtilsHtml
 from .http import TestUtilsHttp
