diff --git a/django/newforms/forms.py b/django/newforms/forms.py
index 2c481e4..6e1c8de 100644
--- a/django/newforms/forms.py
+++ b/django/newforms/forms.py
@@ -64,14 +64,15 @@ class BaseForm(StrAndUnicode):
     # information. Any improvements to the form API should be made to *this*
     # class, not to the Form class.
     def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
-                 initial=None, error_class=ErrorList, label_suffix=':'):
+                 initial=None, error_list=ErrorList, error_dict=ErrorDict, label_suffix=':'):
         self.is_bound = data is not None or files is not None
         self.data = data or {}
         self.files = files or {}
         self.auto_id = auto_id
         self.prefix = prefix
         self.initial = initial or {}
-        self.error_class = error_class
+        self.error_list = error_list
+        self.error_dict = error_dict
         self.label_suffix = label_suffix
         self._errors = None # Stores the errors after clean() has been called.
 
@@ -126,7 +127,7 @@ class BaseForm(StrAndUnicode):
         output, hidden_fields = [], []
         for name, field in self.fields.items():
             bf = BoundField(self, field, name)
-            bf_errors = self.error_class([escape(error) for error in bf.errors]) # Escape and cache in local variable.
+            bf_errors = bf.errors # Escape and cache in local variable.
             if bf.is_hidden:
                 if bf_errors:
                     top_errors.extend([u'(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
@@ -182,14 +183,14 @@ class BaseForm(StrAndUnicode):
         field -- i.e., from Form.clean(). Returns an empty ErrorList if there
         are none.
         """
-        return self.errors.get(NON_FIELD_ERRORS, self.error_class())
+        return self.errors.get(NON_FIELD_ERRORS)
 
     def full_clean(self):
         """
         Cleans all of self.data and populates self._errors and
         self.cleaned_data.
         """
-        self._errors = ErrorDict()
+        self._errors = self.error_dict(error_list=self.error_list)
         if not self.is_bound: # Stop further processing.
             return
         self.cleaned_data = {}
@@ -209,13 +210,13 @@ class BaseForm(StrAndUnicode):
                     value = getattr(self, 'clean_%s' % name)()
                     self.cleaned_data[name] = value
             except ValidationError, e:
-                self._errors[name] = e.messages
+                self._errors[name] = (field.label, e.messages)
                 if name in self.cleaned_data:
                     del self.cleaned_data[name]
         try:
             self.cleaned_data = self.clean()
         except ValidationError, e:
-            self._errors[NON_FIELD_ERRORS] = e.messages
+            self._errors[NON_FIELD_ERRORS] = (u'', e.messages)
         if self._errors:
             delattr(self, 'cleaned_data')
 
@@ -269,7 +270,7 @@ class BoundField(StrAndUnicode):
         Returns an ErrorList for this field. Returns an empty ErrorList
         if there are none.
         """
-        return self.form.errors.get(self.name, self.form.error_class())
+        return self.form.errors.get(self.name)
     errors = property(_errors)
 
     def as_widget(self, widget=None, attrs=None):
diff --git a/django/newforms/util.py b/django/newforms/util.py
index b3edf41..13cc8f5 100644
--- a/django/newforms/util.py
+++ b/django/newforms/util.py
@@ -12,11 +12,9 @@ def flatatt(attrs):
     """
     return u''.join([u' %s="%s"' % (k, escape(v)) for k, v in attrs.items()])
 
-class ErrorDict(dict, StrAndUnicode):
+class ErrorList(list, StrAndUnicode):
     """
     A collection of errors that knows how to display itself in various formats.
-
-    The dictionary keys are the field names, and the values are the errors.
     """
     def __unicode__(self):
         return self.as_ul()
@@ -24,30 +22,50 @@ class ErrorDict(dict, StrAndUnicode):
     def as_ul(self):
         if not self: return u''
         return mark_safe(u'<ul class="errorlist">%s</ul>'
-                % ''.join([u'<li>%s%s</li>' % (k, force_unicode(v))
-                    for k, v in self.items()]))
+                % ''.join([u'<li>%s</li>' % escape(e) for e in self]))
 
     def as_text(self):
-        return u'\n'.join([u'* %s\n%s' % (k, u'\n'.join([u'  * %s' % force_unicode(i) for i in v])) for k, v in self.items()])
+        if not self: return u''
+        return u'\n'.join([u'* %s' % force_unicode(e) for e in self])
 
-class ErrorList(list, StrAndUnicode):
+    def __repr__(self):
+        return repr([force_unicode(e) for e in self])
+
+class ErrorDict(dict, StrAndUnicode):
     """
     A collection of errors that knows how to display itself in various formats.
+
+    The dictionary keys are the field names, and the values are the errors.
     """
+    def __init__(self, error_list=ErrorList):
+        self.error_list = error_list
+
     def __unicode__(self):
         return self.as_ul()
 
+    def __getitem__(self, key):
+        value = super(ErrorDict, self).__getitem__(key)
+        if value:
+            return self.error_list(value[1])
+        return self.error_list()
+
+    def get(self, key, default=None):
+        value = super(ErrorDict, self).get(key, default)
+        if value:
+            return self.error_list(value[1])
+        return self.error_list()
+
     def as_ul(self):
         if not self: return u''
         return mark_safe(u'<ul class="errorlist">%s</ul>'
-                % ''.join([u'<li>%s</li>' % force_unicode(e) for e in self]))
+                % ''.join([u'<li>%s%s</li>' % (v[0] and escape(v[0]) or k, force_unicode(self.error_list(v[1])))
+                    for k, v in self.items()]))
 
     def as_text(self):
-        if not self: return u''
-        return u'\n'.join([u'* %s' % force_unicode(e) for e in self])
+        return u'\n'.join([u'* %s\n%s' % (v[0] and force_unicode(v[0]) or k, u'\n'.join([u'  * %s' % force_unicode(i) for i in v[1]])) for k, v in self.items()])
 
     def __repr__(self):
-        return repr([force_unicode(e) for e in self])
+        return repr(dict([(k, v[1]) for k, v in self.items()]))
 
 class ValidationError(Exception):
     def __init__(self, message):
diff --git a/django/test/_doctest.py b/django/test/_doctest.py
index a56483c..6d66a8d 100644
--- a/django/test/_doctest.py
+++ b/django/test/_doctest.py
@@ -503,7 +503,7 @@ class DocTest:
         self.globs = globs.copy()
         self.name = name
         self.filename = filename
-        self.lineno = lineno
+        self.lineno = lineno or 0
 
     def __repr__(self):
         if len(self.examples) == 0:
diff --git a/tests/regressiontests/forms/extra.py b/tests/regressiontests/forms/extra.py
index 9dff407..6b29324 100644
--- a/tests/regressiontests/forms/extra.py
+++ b/tests/regressiontests/forms/extra.py
@@ -369,7 +369,7 @@ u'sirrobin'
 ...     email = EmailField()
 ...     comment = CharField()
 >>> data = dict(email='invalid')
->>> f = CommentForm(data, auto_id=False, error_class=DivErrorList)
+>>> f = CommentForm(data, auto_id=False, error_list=DivErrorList)
 >>> print f.as_p()
 <p>Name: <input type="text" name="name" maxlength="50" /></p>
 <div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div>
