diff --git a/django/contrib/admin/media/js/admin/RelatedObjectLookups.js b/django/contrib/admin/media/js/admin/RelatedObjectLookups.js
index d201f39..4bcff7f 100644
--- a/django/contrib/admin/media/js/admin/RelatedObjectLookups.js
+++ b/django/contrib/admin/media/js/admin/RelatedObjectLookups.js
@@ -41,6 +41,15 @@ function showRelatedObjectLookupPopup(triggeringLink) {
     return false;
 }
 
+function showGenericRelatedObjectLookupPopup(ct_select, triggering_link, url_base) {
+    var url = content_types[ct_select.options[ct_select.selectedIndex].value];
+    if (url != undefined) {
+        triggering_link.href = url_base + url;
+        return showRelatedObjectLookupPopup(triggering_link);
+    }
+    return false;
+}
+
 function dismissRelatedLookupPopup(win, chosenId) {
     var name = windowname_to_id(win.name);
     var elem = document.getElementById(name);
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 3d60b9d..4ba49bc 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -38,6 +38,7 @@ class BaseModelAdmin(object):
     filter_horizontal = ()
     radio_fields = {}
     prepopulated_fields = {}
+    generic_fields = ()
 
     def formfield_for_dbfield(self, db_field, **kwargs):
         """
@@ -63,6 +64,13 @@ class BaseModelAdmin(object):
             else:
                 # Otherwise, use the default select widget.
                 return db_field.formfield(**kwargs)
+        
+        # For generic foreign keys marked as generic_fields we use a special widget
+        if 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()))
 
         # For DateTimeFields, use a special field and widget.
         if isinstance(db_field, models.DateTimeField):
diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py
index ccade8a..779c91d 100644
--- a/django/contrib/admin/validation.py
+++ b/django/contrib/admin/validation.py
@@ -102,6 +102,14 @@ def validate(cls, model):
         if not isinstance(getattr(cls, attr), bool):
             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 291bee0..aa69d70 100644
--- a/django/contrib/admin/widgets.py
+++ b/django/contrib/admin/widgets.py
@@ -278,3 +278,40 @@ 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)]
+        output.append("""
+            <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})
+        output.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="%s" /></a>' % (settings.ADMIN_MEDIA_PREFIX, _('Lookup')))
+        if value:
+            output.append(self.label_for_value(value))
+        
+        from django.contrib.contenttypes.models import ContentType
+        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/docs/ref/contrib/admin.txt b/docs/ref/contrib/admin.txt
index f24dc46..7fb1ae4 100644
--- a/docs/ref/contrib/admin.txt
+++ b/docs/ref/contrib/admin.txt
@@ -238,6 +238,12 @@ list of fields that should be displayed as a horizontal filter interface. See
 Same as ``filter_horizontal``, but is a vertical display of the filter
 interface.
 
+``generic_fields``
+~~~~~~~~~~~~~~~~~~
+
+This is a list of ``GenericForeignKeys`` that will have an interface similar to 
+that of ``raw_id_fields``.
+
 ``list_display``
 ~~~~~~~~~~~~~~~~
 
diff --git a/tests/regressiontests/admin_widgets/models.py b/tests/regressiontests/admin_widgets/models.py
index ddfc6c2..bf478f0 100644
--- a/tests/regressiontests/admin_widgets/models.py
+++ b/tests/regressiontests/admin_widgets/models.py
@@ -2,6 +2,8 @@
 from django.conf import settings
 from django.db import models
 from django.core.files.storage import default_storage
+from django.contrib.contenttypes import generic
+from django.contrib.contenttypes.models import ContentType
 
 class Member(models.Model):
     name = models.CharField(max_length=100)
@@ -41,6 +43,17 @@ class Inventory(models.Model):
    def __unicode__(self):
       return self.name
 
+class Image(models.Model):
+    image = models.ImageField(upload_to='images')
+    description = models.CharField(max_length=200)
+
+    content_type = models.ForeignKey(ContentType)
+    object_id = models.PositiveIntegerField()
+    object = generic.GenericForeignKey('content_type', 'object_id')
+    
+    def __unicode__(self):
+        return u"%s - %s" % (self.image.name, self.description[:100])
+
 __test__ = {'WIDGETS_TESTS': """
 >>> from datetime import datetime
 >>> from django.utils.html import escape, conditional_escape
@@ -48,6 +61,7 @@ __test__ = {'WIDGETS_TESTS': """
 >>> from django.contrib.admin.widgets import FilteredSelectMultiple, AdminSplitDateTime
 >>> from django.contrib.admin.widgets import AdminFileWidget, ForeignKeyRawIdWidget, ManyToManyRawIdWidget
 >>> from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
+>>> from django.contrib.admin.widgets import GenericForeignKeyRawIdWidget
 
 Calling conditional_escape on the output of widget.render will simulate what
 happens in the template. This is easier than setting up a template and context
@@ -116,6 +130,23 @@ True
 >>> child_of_hidden = Inventory.objects.create(barcode=94, name='Child of hidden', parent=hidden)
 >>> print w.render('test', child_of_hidden.parent_id, attrs={}) 
 <input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" /><a href="../../../admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a>&nbsp;<strong>Hidden</strong>
+
+>>> print GenericForeignKeyRawIdWidget(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="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a>
+            <script type="text/javascript">
+            var content_types = new Array();
+            </script>
+
+>>> print GenericForeignKeyRawIdWidget(Image._meta.virtual_fields[0].ct_field, [x.model_class() for x in ContentType.objects.filter(pk__lt=3)]).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="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a>
+    <script type="text/javascript">
+    var content_types = new Array();
+        content_types[1] = 'contenttypes/contenttype/';
+content_types[2] = 'auth/permission/';
+    </script>
+    
 """ % {
     'ADMIN_MEDIA_PREFIX': settings.ADMIN_MEDIA_PREFIX,
     'STORAGE_URL': default_storage.url(''),
diff --git a/tests/regressiontests/modeladmin/models.py b/tests/regressiontests/modeladmin/models.py
index 3a7d3f0..eba5061 100644
--- a/tests/regressiontests/modeladmin/models.py
+++ b/tests/regressiontests/modeladmin/models.py
@@ -3,6 +3,8 @@ from datetime import date
 
 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)
@@ -35,6 +37,15 @@ 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)
+    object_id = models.PositiveIntegerField()
+    object = generic.GenericForeignKey('content_type', 'object_id')
+
+
 __test__ = {'API_TESTS': """
 
 >>> from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL
@@ -912,5 +923,22 @@ ImproperlyConfigured: 'ValidationTestInline.formset' does not inherit from BaseM
 ...     inlines = [ValidationTestInline]
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 
+>>> class GenericModelAdmin(ModelAdmin):
+...     generic_fields = None
+>>> validate(GenericModelAdmin, Image)
+Traceback (most recent call last):
+...
+ImproperlyConfigured: 'GenericModelAdmin.generic_fields' must be a list or tuple.
+>>> class GenericModelAdmin(ModelAdmin):
+...     generic_fields = ["abc"]
+>>> validate(GenericModelAdmin, Image)
+Traceback (most recent call last):
+...
+ImproperlyConfigured: Item number 0 in GenericModelAdmin.generic_fieldsis not a GenericForeignKey on Image
+
+>>> class GenericModelAdmin(ModelAdmin):
+...     generic_fields = ["object"]
+>>> validate(GenericModelAdmin, Image)
+
 """
 }
