diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 4ddf901ea5..ce5ed343b0 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -305,7 +305,13 @@ class Field(object):
         "Returns a django.forms.Field instance for this database Field."
         defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
         if self.choices:
-            defaults['widget'] = forms.Select(choices=self.get_choices(include_blank=self.blank or not (self.has_default() or 'initial' in kwargs)))
+            form_class = forms.TypedChoiceField
+            include_blank = self.blank or not (self.has_default() or 'initial' in kwargs)
+            defaults['choices'] = self.get_choices(include_blank=include_blank)
+            defaults['coerce'] = self.to_python
+            if self.null:
+                defaults['empty_value'] = None
+            kwargs.pop('max_length', None)
         if self.has_default():
             defaults['initial'] = self.get_default()
         defaults.update(kwargs)
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index 0ea20751d9..5f714fbedb 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -27,6 +27,12 @@ ARTICLE_STATUS = (
     (3, 'Live'),
 )
 
+ARTICLE_STATUS_CHAR = (
+    ('d', 'Draft'),
+    ('p', 'Pending'),
+    ('l', 'Live'),
+)
+
 class Category(models.Model):
     name = models.CharField(max_length=20)
     slug = models.SlugField(max_length=20)
@@ -111,6 +117,9 @@ class CommaSeparatedInteger(models.Model):
     def __unicode__(self):
         return self.field
 
+class ArticleStatus(models.Model):
+    status = models.CharField(max_length=2, choices=ARTICLE_STATUS_CHAR, blank=True, null=True)
+
 __test__ = {'API_TESTS': """
 >>> from django import forms
 >>> from django.forms.models import ModelForm, model_to_dict
@@ -1123,4 +1132,24 @@ u'1,,2'
 >>> f.clean('1')
 u'1'
 
+# Choices on CharField and IntegerField
+
+>>> class ArticleForm(ModelForm):
+...     class Meta:
+...         model = Article
+>>> f = ArticleForm()
+>>> f.fields['status'].clean('42')
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. 42 is not one of the available choices.']
+
+>>> class ArticleStatusForm(ModelForm):
+...     class Meta:
+...         model = ArticleStatus
+>>> f = ArticleStatusForm()
+>>> f.fields['status'].clean('z')
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. z is not one of the available choices.']
+
 """}