Index: docs/ref/class-based-views.txt
===================================================================
--- docs/ref/class-based-views.txt	(revision 15284)
+++ docs/ref/class-based-views.txt	(working copy)
@@ -140,6 +140,10 @@
 
         Designates the name of the variable to use in the context.
 
+    .. method:: get_model()
+        Retrieve the model to instantiate. By default
+        :attr:`.model`.
+
     .. method:: get_object(queryset=None)
 
         Returns the single object that this view will display. If
@@ -488,6 +492,13 @@
         example, you could use ``success_url="/polls/%(slug)s/"`` to
         redirect to a URL composed out of the ``slug`` field on a model.
 
+    .. method:: get_model()
+        Retrieve the model to instantiate. By default
+        :attr:`~SingleObjectMixin.model` will be used if provided.
+        Otherwise it'll use :attr:`~FormMixin.form_class` and lastly
+        :attr:`~SingleObjectMixin.queryset`, which will raise an 
+        ImproperlyConfigured exception if none of them are set.
+
     .. method:: get_form_class()
 
         Retrieve the form class to instantiate. If
Index: tests/regressiontests/generic_views/edit.py
===================================================================
--- tests/regressiontests/generic_views/edit.py	(revision 15284)
+++ tests/regressiontests/generic_views/edit.py	(working copy)
@@ -201,6 +201,17 @@
         except ImproperlyConfigured:
             pass
 
+    def test_update_with_form_class(self):
+        a = Author.objects.create(
+            name='Randall Munroe',
+            slug='randall-munroe',
+        )
+        res = self.client.post('/edit/author/%d/update/formclass/' % a.pk,
+                        {'name': 'Randall Munroe (author of xkcd)', 'slug': 'randall-munroe'})
+        self.assertEqual(res.status_code, 302)
+        self.assertRedirects(res, 'http://testserver/edit/authors/create/')
+        self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (author of xkcd)>'])
+
 class DeleteViewTests(TestCase):
     urls = 'regressiontests.generic_views.urls'
 
Index: tests/regressiontests/generic_views/urls.py
===================================================================
--- tests/regressiontests/generic_views/urls.py	(revision 15284)
+++ tests/regressiontests/generic_views/urls.py	(working copy)
@@ -1,5 +1,6 @@
 from django.conf.urls.defaults import *
-from django.views.generic import TemplateView
+from django.views.generic import TemplateView, UpdateView
+from regressiontests.generic_views.forms import AuthorForm
 
 import views
 
@@ -64,6 +65,9 @@
         views.NaiveAuthorUpdate.as_view()),
     (r'^edit/author/(?P<pk>\d+)/update/redirect/$',
         views.NaiveAuthorUpdate.as_view(success_url='/edit/authors/create/')),
+    (r'^edit/author/(?P<pk>\d+)/update/formclass/$',
+        UpdateView.as_view(form_class=AuthorForm, 
+            success_url='/edit/authors/create/')),
     (r'^edit/author/(?P<pk>\d+)/update/interpolate_redirect/$',
         views.NaiveAuthorUpdate.as_view(success_url='/edit/author/%(id)d/update/')),
     (r'^edit/author/(?P<pk>\d+)/update/$',
Index: django/views/generic/detail.py
===================================================================
--- django/views/generic/detail.py	(revision 15284)
+++ django/views/generic/detail.py	(working copy)
@@ -15,6 +15,9 @@
     slug_field = 'slug'
     context_object_name = None
 
+    def get_model(self):
+        return self.model
+
     def get_object(self, queryset=None):
         """
         Returns the object the view is displaying.
@@ -57,8 +60,8 @@
         `get_object` is overridden.
         """
         if self.queryset is None:
-            if self.model:
-                return self.model._default_manager.all()
+            if self.get_model():
+                return self.get_model()._default_manager.all()
             else:
                 raise ImproperlyConfigured(u"%(cls)s is missing a queryset. Define "
                                            u"%(cls)s.model, %(cls)s.queryset, or override "
@@ -127,10 +130,10 @@
                 self.object._meta.object_name.lower(),
                 self.template_name_suffix
             ))
-        elif hasattr(self, 'model') and hasattr(self.model, '_meta'):
+        elif hasattr(self, 'model') and hasattr(self.get_model(), '_meta'):
             names.append("%s/%s%s.html" % (
-                self.model._meta.app_label,
-                self.model._meta.object_name.lower(),
+                self.get_model()._meta.app_label,
+                self.get_model()._meta.object_name.lower(),
                 self.template_name_suffix
             ))
         return names
Index: django/views/generic/edit.py
===================================================================
--- django/views/generic/edit.py	(revision 15284)
+++ django/views/generic/edit.py	(working copy)
@@ -68,6 +68,14 @@
     A mixin that provides a way to show and handle a modelform in a request.
     """
 
+    def get_model(self):
+        model = super(ModelFormMixin, self).get_model()
+
+        if model:
+            return model
+        elif self.get_form_class(): 
+            return self.get_form_class()._meta.model
+
     def get_form_class(self):
         """
         Returns the form class to use in this view
