diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 1634d7d..8a86742 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -8,8 +8,9 @@ from django.db.models.related import RelatedObject
 from django.db.models.query import QuerySet
 from django.db.models.query_utils import QueryWrapper
 from django.utils.encoding import smart_unicode
-from django.utils.translation import ugettext_lazy as _, string_concat, ungettext, ugettext
-from django.utils.functional import curry
+from django.utils.translation import (ugettext_lazy as _, string_concat, 
+    ungettext, ugettext)
+from django.utils.functional import curry, cached_property, memoize
 from django.core import exceptions
 from django import forms
 
@@ -373,9 +374,10 @@ class ForeignRelatedObjectsDescriptor(object):
     def __get__(self, instance, instance_type=None):
         if instance is None:
             return self
-
-        return self.create_manager(instance,
-                self.related.model._default_manager.__class__)
+        manager = self.create_manager(
+            self.related.model._default_manager.__class__
+        )
+        return manager(instance)
 
     def __set__(self, instance, value):
         if instance is None:
@@ -394,10 +396,10 @@ class ForeignRelatedObjectsDescriptor(object):
         than the default manager, as returned by __get__). Used by
         Model.delete().
         """
-        return self.create_manager(instance,
-                self.related.model._base_manager.__class__)
+        manager = self.create_manager(self.related.model._base_manager.__class__)
+        return manager(instance)
 
-    def create_manager(self, instance, superclass):
+    def create_manager(self, superclass):
         """
         Creates the managers used by other methods (__get__() and delete()).
         """
@@ -405,43 +407,55 @@ class ForeignRelatedObjectsDescriptor(object):
         rel_model = self.related.model
 
         class RelatedManager(superclass):
+            def __init__(self, instance):
+                super(RelatedManager, self).__init__()
+                attname = rel_field.rel.get_related_field().name
+                self.instance = instance
+                self.core_filters = {
+                    '%s__%s' % (rel_field.name, attname): getattr(instance, attname)
+                }
+                self.model = rel_model
+            
             def get_query_set(self):
-                db = self._db or router.db_for_read(rel_model, instance=instance)
-                return superclass.get_query_set(self).using(db).filter(**(self.core_filters))
+                db = self._db or router.db_for_read(
+                    rel_model, instance=self.instance
+                )
+                return superclass.get_query_set(self).using(db).filter(**self.core_filters)
 
             def add(self, *objs):
                 for obj in objs:
                     if not isinstance(obj, self.model):
                         raise TypeError("'%s' instance expected" % self.model._meta.object_name)
-                    setattr(obj, rel_field.name, instance)
+                    setattr(obj, rel_field.name, self.instance)
                     obj.save()
             add.alters_data = True
 
             def create(self, **kwargs):
-                kwargs.update({rel_field.name: instance})
-                db = router.db_for_write(rel_model, instance=instance)
+                kwargs.update({rel_field.name: self.instance})
+                db = router.db_for_write(rel_model, instance=self.instance)
                 return super(RelatedManager, self).using(db).create(**kwargs)
             create.alters_data = True
 
             def get_or_create(self, **kwargs):
                 # Update kwargs with the related object that this
                 # ForeignRelatedObjectsDescriptor knows about.
-                kwargs.update({rel_field.name: instance})
-                db = router.db_for_write(rel_model, instance=instance)
+                kwargs.update({rel_field.name: self.instance})
+                db = router.db_for_write(rel_model, instance=self.instance)
                 return super(RelatedManager, self).using(db).get_or_create(**kwargs)
             get_or_create.alters_data = True
 
-            # remove() and clear() are only provided if the ForeignKey can have a value of null.
+            # remove() and clear() are only provided if the ForeignKey can have
+            # a value of null.
             if rel_field.null:
                 def remove(self, *objs):
-                    val = getattr(instance, rel_field.rel.get_related_field().attname)
+                    val = getattr(self.instance, rel_field.rel.get_related_field().attname)
                     for obj in objs:
                         # Is obj actually part of this descriptor set?
                         if getattr(obj, rel_field.attname) == val:
                             setattr(obj, rel_field.name, None)
                             obj.save()
                         else:
-                            raise rel_field.rel.to.DoesNotExist("%r is not related to %r." % (obj, instance))
+                            raise rel_field.rel.to.DoesNotExist("%r is not related to %r." % (obj, self.instance))
                 remove.alters_data = True
 
                 def clear(self):
@@ -450,13 +464,8 @@ class ForeignRelatedObjectsDescriptor(object):
                         obj.save()
                 clear.alters_data = True
 
-        manager = RelatedManager()
-        attname = rel_field.rel.get_related_field().name
-        manager.core_filters = {'%s__%s' % (rel_field.name, attname):
-                getattr(instance, attname)}
-        manager.model = self.related.model
-
-        return manager
+        return RelatedManager
+    create_manager = memoize(create_manager, {}, 2)
 
 def create_many_related_manager(superclass, rel=False):
     """Creates a manager that subclasses 'superclass' (which is a Manager)
@@ -645,18 +654,22 @@ class ManyRelatedObjectsDescriptor(object):
     # ManyRelatedObjectsDescriptor instance.
     def __init__(self, related):
         self.related = related   # RelatedObject instance
+    
+    @cached_property
+    def related_manager_cls(self):
+        # Dynamically create a class that subclasses the related
+        # model's default manager.
+        return create_many_related_manager(
+            self.related.model._default_manager.__class__,
+            self.related.field.rel
+        )
 
     def __get__(self, instance, instance_type=None):
         if instance is None:
             return self
 
-        # Dynamically create a class that subclasses the related
-        # model's default manager.
         rel_model = self.related.model
-        superclass = rel_model._default_manager.__class__
-        RelatedManager = create_many_related_manager(superclass, self.related.field.rel)
-
-        manager = RelatedManager(
+        manager = self.related_manager_cls(
             model=rel_model,
             core_filters={'%s__pk' % self.related.field.name: instance._get_pk_val()},
             instance=instance,
@@ -690,6 +703,15 @@ class ReverseManyRelatedObjectsDescriptor(object):
     # ReverseManyRelatedObjectsDescriptor instance.
     def __init__(self, m2m_field):
         self.field = m2m_field
+    
+    @cached_property
+    def related_manager_cls(self):
+        # Dynamically create a class that subclasses the related model's
+        # default manager.
+        return create_many_related_manager(
+            self.field.rel.to._default_manager.__class__,
+            self.field.rel
+        )
 
     def _through(self):
         # through is provided so that you have easy access to the through
@@ -701,15 +723,9 @@ class ReverseManyRelatedObjectsDescriptor(object):
     def __get__(self, instance, instance_type=None):
         if instance is None:
             return self
-
-        # Dynamically create a class that subclasses the related
-        # model's default manager.
-        rel_model=self.field.rel.to
-        superclass = rel_model._default_manager.__class__
-        RelatedManager = create_many_related_manager(superclass, self.field.rel)
-
-        manager = RelatedManager(
-            model=rel_model,
+        
+        manager = self.related_manager_cls(
+            model=self.field.rel.to,
             core_filters={'%s__pk' % self.field.related_query_name(): instance._get_pk_val()},
             instance=instance,
             symmetrical=self.field.rel.symmetrical,
@@ -1022,7 +1038,7 @@ class ManyToManyField(RelatedField, Field):
         if hasattr(self, cache_attr):
             return getattr(self, cache_attr)
         for f in self.rel.through._meta.fields:
-            if hasattr(f,'rel') and f.rel and f.rel.to == related.model:
+            if hasattr(f, 'rel') and f.rel and f.rel.to == related.model:
                 setattr(self, cache_attr, getattr(f, attr))
                 return getattr(self, cache_attr)
 
@@ -1049,25 +1065,6 @@ class ManyToManyField(RelatedField, Field):
                     break
         return getattr(self, cache_attr)
 
-    def isValidIDList(self, field_data, all_data):
-        "Validates that the value is a valid list of foreign keys"
-        mod = self.rel.to
-        try:
-            pks = map(int, field_data.split(','))
-        except ValueError:
-            # the CommaSeparatedIntegerField validator will catch this error
-            return
-        objects = mod._default_manager.in_bulk(pks)
-        if len(objects) != len(pks):
-            badkeys = [k for k in pks if k not in objects]
-            raise exceptions.ValidationError(
-                ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.",
-                          "Please enter valid %(self)s IDs. The values %(value)r are invalid.",
-                          len(badkeys)) % {
-                'self': self.verbose_name,
-                'value': len(badkeys) == 1 and badkeys[0] or tuple(badkeys),
-            })
-
     def value_to_string(self, obj):
         data = ''
         if obj:
diff --git a/django/utils/functional.py b/django/utils/functional.py
index ccfbcb0..ed6fc57 100644
--- a/django/utils/functional.py
+++ b/django/utils/functional.py
@@ -126,6 +126,14 @@ def memoize(func, cache, num_args):
         return result
     return wraps(func)(wrapper)
 
+class cached_property(object):
+    def __init__(self, func):
+        self.func = func
+    
+    def __get__(self, instance, type):
+        res = instance.__dict__[self.func.__name__] = self.func(instance)
+        return res
+
 class Promise(object):
     """
     This is just a base class for the proxy class created in
diff --git a/tests/regressiontests/m2m_regress/tests.py b/tests/regressiontests/m2m_regress/tests.py
new file mode 100644
index 0000000..cbd54af
--- /dev/null
+++ b/tests/regressiontests/m2m_regress/tests.py
@@ -0,0 +1,16 @@
+from django.test import TestCase
+
+from models import Entry, Tag
+
+
+class M2MTests(TestCase):
+    def test_manager_class(self):
+        e1 = Entry.objects.create()
+        e2 = Entry.objects.create()
+        t1 = Tag.objects.create()
+        t2 = Tag.objects.create()
+        self.assertTrue(e1.topics.__class__ is e1.topics.__class__)
+        self.assertTrue(e2.topics.__class__ is e2.topics.__class__)
+        
+        self.assertTrue(t1.entry_set.__class__ is t1.entry_set.__class__)
+        self.assertTrue(t1.entry_set.__class__ is t2.entry_set.__class__)
