diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index f05b5cb..1ac9d11 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -72,6 +72,7 @@ class BaseModelAdmin(object):
     formfield_overrides = {}
     readonly_fields = ()
     ordering = None
+    generic_fields = ()
 
     def __init__(self):
         overrides = FORMFIELD_FOR_DBFIELD_DEFAULTS.copy()
@@ -122,6 +123,19 @@ class BaseModelAdmin(object):
 
             return formfield
 
+        # For generic foreign keys marked as generic_fields we use a special widget
+        elif db_field.name in [f.fk_field for f
+                             in self.model._meta.virtual_fields
+                             if f.name in self.generic_fields]:
+            for gfk in self.model._meta.virtual_fields:
+                if gfk.fk_field == db_field.name:
+                    break
+            return db_field.formfield(
+                label=capfirst(gfk.name.replace('_', ' ')),
+                widget=widgets.GenericForeignKeyRawIdWidget(
+                    gfk.ct_field,
+                    self.admin_site._registry.keys()))
+
         # If we've got overrides for the formfield defined, use 'em. **kwargs
         # passed to formfield_for_dbfield override the defaults.
         for klass in db_field.__class__.mro():
diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py
index 733f89d..0812407 100644
--- a/django/contrib/admin/validation.py
+++ b/django/contrib/admin/validation.py
@@ -171,6 +171,14 @@ def validate(cls, model):
             raise ImproperlyConfigured("'%s.%s' should be a boolean."
                     % (cls.__name__, attr))
 
+    if hasattr(cls, 'generic_fields'):
+        check_isseq(cls, 'generic_fields', cls.generic_fields)
+        for i, field in enumerate(cls.generic_fields):
+            if field not in [f.name for f in model._meta.virtual_fields]:
+                raise ImproperlyConfigured(
+                    "Item number %d in %s.generic_fields"
+                    "is not a GenericForeignKey on %s"
+                    % (i, cls.__name__, model.__name__))
 
     # inlines = []
     if hasattr(cls, 'inlines'):
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py
index 0d1f2a9..b87c366 100644
--- a/django/contrib/admin/widgets.py
+++ b/django/contrib/admin/widgets.py
@@ -5,6 +5,7 @@ Form Widget classes specific to the Django admin site.
 import copy
 from django import forms
 from django.contrib.admin.templatetags.admin_static import static
+from django.contrib.contenttypes.models import ContentType
 from django.core.urlresolvers import reverse
 from django.forms.widgets import RadioFieldRenderer
 from django.forms.util import flatatt
@@ -309,3 +310,47 @@ class AdminCommaSeparatedIntegerFieldWidget(forms.TextInput):
         if attrs is not None:
             final_attrs.update(attrs)
         super(AdminCommaSeparatedIntegerFieldWidget, self).__init__(attrs=final_attrs)
+
+class GenericForeignKeyRawIdWidget(ForeignKeyRawIdWidget):
+    def __init__(self, ct_field, cts=[], attrs=None):
+        self.ct_field = ct_field
+        self.cts = cts
+        forms.TextInput.__init__(self, attrs)
+
+    def render(self, name, value, attrs=None):
+        if attrs is None:
+            attrs = {}
+        related_url = '../../../'
+        params = self.url_parameters()
+        if params:
+            url = '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in params.iteritems()])
+        else:
+            url = ''
+        if 'class' not in attrs:
+            attrs['class'] = 'vForeignKeyRawIdAdminField'
+        output = [
+            forms.TextInput.render(self, name, value, attrs),
+            "<a href=\"%(related)s%(url)s\" class=\"related-lookup\" "
+            "id=\"lookup_id_%(name)s\" onclick=\"return "
+            "showGenericRelatedObjectLookupPopup(document.getElementById("
+            "'id_%(ct_field)s'), this, '%(related)s%(url)s');\"> "
+                % {'related': related_url, 'url': url, 'name': name,
+                   'ct_field': self.ct_field},
+            "<img src=\"%s\" width=\"16\" height=\"16\" alt=\"%s\" /></a>"
+                % (static('admin/img/selector-search.gif'), _('Lookup'))]
+        if value:
+            output.append(self.label_for_value(value))
+
+        content_types = """
+<script type="text/javascript">
+var content_types = new Array();
+%s
+</script>""" % ('\n'.join(["content_types[%s] = '%s/%s/';"
+                           % (ContentType.objects.get_for_model(ct).id,
+                              ct._meta.app_label,
+                              ct._meta.object_name.lower())
+                           for ct in self.cts]))
+        return mark_safe(u''.join(output) + content_types)
+
+    def url_parameters(self):
+        return {}
diff --git a/tests/regressiontests/admin_widgets/models.py b/tests/regressiontests/admin_widgets/models.py
index c4489e0..8e16641 100644
--- a/tests/regressiontests/admin_widgets/models.py
+++ b/tests/regressiontests/admin_widgets/models.py
@@ -1,6 +1,7 @@
 from django.db import models
 from django.contrib.auth.models import User
-
+from django.contrib.contenttypes import generic
+from django.contrib.contenttypes.models import ContentType
 
 class MyFileField(models.FileField):
     pass
@@ -99,3 +100,14 @@ class Advisor(models.Model):
     """
     name = models.CharField(max_length=20)
     companies = models.ManyToManyField(Company)
+
+class Image(models.Model):
+    image = models.ImageField(upload_to='images')
+    description = models.CharField(max_length=200)
+
+    content_type = models.ForeignKey(ContentType, related_name='admin_widgets_image_set')
+    object_id = models.PositiveIntegerField()
+    object = generic.GenericForeignKey('content_type', 'object_id')
+
+    def __unicode__(self):
+        return u"%s - %s" % (self.image.name, self.description[:100])
\ No newline at end of file
diff --git a/tests/regressiontests/admin_widgets/tests.py b/tests/regressiontests/admin_widgets/tests.py
index a7bfe55..0c03916 100644
--- a/tests/regressiontests/admin_widgets/tests.py
+++ b/tests/regressiontests/admin_widgets/tests.py
@@ -7,6 +7,7 @@ from django import forms
 from django.conf import settings
 from django.contrib import admin
 from django.contrib.admin import widgets
+from django.contrib.contenttypes.models import ContentType
 from django.core.files.storage import default_storage
 from django.core.files.uploadedfile import SimpleUploadedFile
 from django.db.models import DateField
@@ -14,6 +15,7 @@ from django.test import TestCase as DjangoTestCase
 from django.utils import translation
 from django.utils.html import conditional_escape
 from django.utils.unittest import TestCase
+from django.contrib.admin.widgets import GenericForeignKeyRawIdWidget
 
 import models
 from widgetadmin import site as widget_admin_site
@@ -148,6 +150,32 @@ class AdminForeignKeyWidgetChangeList(DjangoTestCase):
         self.assertTrue('%s/auth/user/add/' % self.admin_root in response.content)
 
 
+class AdminGenericForeignKeyRawIdWidget(DjangoTestCase):
+    fixtures = ["admin-widgets-users.xml"]
+    admin_root = '/widget_admin'
+
+    def test_gfk_raw_id_field(self):
+        self.assertEqual(
+            GenericForeignKeyRawIdWidget(models.Image._meta.virtual_fields[0].ct_field).render('test', '', {}),
+            """<input type="text" name="test" class="vForeignKeyRawIdAdminField" /><a href="../../../" class="related-lookup" id="lookup_id_test" onclick="return showGenericRelatedObjectLookupPopup(document.getElementById('id_content_type'), this, '../../../');"> <img src="/static/admin/img/selector-search.gif" width="16" height="16" alt="Lookup" /></a>
+<script type="text/javascript">
+var content_types = new Array();
+
+</script>"""
+        )
+
+        cts = [ct.model_class() for ct in ContentType.objects.filter(pk__lt=3)]
+        self.assertEqual(
+            GenericForeignKeyRawIdWidget(models.Image._meta.virtual_fields[0].ct_field, cts).render('test', '', {}),
+            """<input type="text" name="test" class="vForeignKeyRawIdAdminField" /><a href="../../../" class="related-lookup" id="lookup_id_test" onclick="return showGenericRelatedObjectLookupPopup(document.getElementById('id_content_type'), this, '../../../');"> <img src="/static/admin/img/selector-search.gif" width="16" height="16" alt="Lookup" /></a>
+<script type="text/javascript">
+var content_types = new Array();
+content_types[1] = '%s/%s/';
+content_types[2] = '%s/%s/';
+</script>""" % (cts[0]._meta.app_label, cts[0]._meta.object_name.lower(),
+                cts[1]._meta.app_label, cts[1]._meta.object_name.lower(),)
+        )
+
 class AdminForeignKeyRawIdWidget(DjangoTestCase):
     fixtures = ["admin-widgets-users.xml"]
     admin_root = '/widget_admin'
diff --git a/tests/regressiontests/modeladmin/models.py b/tests/regressiontests/modeladmin/models.py
index ae180a4..e296169 100644
--- a/tests/regressiontests/modeladmin/models.py
+++ b/tests/regressiontests/modeladmin/models.py
@@ -1,6 +1,8 @@
 # coding: utf-8
 from django.db import models
 from django.contrib.auth.models import User
+from django.contrib.contenttypes import generic
+from django.contrib.contenttypes.models import ContentType
 
 class Band(models.Model):
     name = models.CharField(max_length=100)
@@ -39,3 +41,11 @@ class ValidationTestModel(models.Model):
 
 class ValidationTestInlineModel(models.Model):
     parent = models.ForeignKey(ValidationTestModel)
+
+class Image(models.Model):
+    image = models.ImageField(upload_to='pictures')
+    description = models.TextField()
+
+    content_type = models.ForeignKey(ContentType, related_name='modeladmin_image_set')
+    object_id = models.PositiveIntegerField()
+    object = generic.GenericForeignKey('content_type', 'object_id')
\ No newline at end of file
diff --git a/tests/regressiontests/modeladmin/tests.py b/tests/regressiontests/modeladmin/tests.py
index 872fb0c..819a779 100644
--- a/tests/regressiontests/modeladmin/tests.py
+++ b/tests/regressiontests/modeladmin/tests.py
@@ -16,7 +16,7 @@ from django.test import TestCase
 from django.utils import unittest
 
 from models import (Band, Concert, ValidationTestModel,
-    ValidationTestInlineModel)
+    ValidationTestInlineModel, Image)
 
 
 # None of the following tests really depend on the content of the request,
@@ -1486,3 +1486,31 @@ class ValidationTests(unittest.TestCase):
             inlines = [ValidationTestInline]
 
         validate(ValidationTestModelAdmin, ValidationTestModel)
+
+    def test_generic_fields_validation(self):
+        class GenericModelAdmin(ModelAdmin):
+            generic_fields = None
+
+        self.assertRaisesRegexp(
+            ImproperlyConfigured,
+                "'GenericModelAdmin.generic_fields' must be a list or tuple.",
+            validate,
+            GenericModelAdmin,
+            Image
+        )
+
+        class GenericModelAdmin(ModelAdmin):
+            generic_fields = ["abc"]
+
+        self.assertRaisesRegexp(
+            ImproperlyConfigured,
+                "Item number 0 in GenericModelAdmin.generic_fieldsis not a GenericForeignKey on Image",
+            validate,
+            GenericModelAdmin,
+            Image
+        )
+
+        class GenericModelAdmin(ModelAdmin):
+            generic_fields = ["object"]
+
+        validate(GenericModelAdmin, Image)
\ No newline at end of file
