diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ModelStateDictionaryExtensions.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ModelStateDictionaryExtensions.cs
new file mode 100644
index 0000000000..1dfce56095
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ModelStateDictionaryExtensions.cs
@@ -0,0 +1,114 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Linq;
+using System.Linq.Expressions;
+using Microsoft.AspNet.Mvc.ModelBinding;
+using Microsoft.AspNet.Mvc.ViewFeatures;
+
+namespace Microsoft.AspNet.Mvc
+{
+ ///
+ /// Extensions methods for .
+ ///
+ public static class ModelStateDictionaryExtensions
+ {
+ ///
+ /// Adds the specified to the instance
+ /// that is associated with the specified .
+ ///
+ /// The type of the model.
+ /// The instance this method extends.
+ /// An expression to be evaluated against an item in the current model.
+ /// The error message to add.
+ public static void AddModelError(this ModelStateDictionary modelState, Expression> expression, string errorMessage)
+ {
+ modelState.AddModelError(GetExpressionText(expression), errorMessage);
+ }
+
+ ///
+ /// Adds the specified to the instance
+ /// that is associated with the specified .
+ ///
+ /// The type of the model.
+ /// The instance this method extends.
+ /// An expression to be evaluated against an item in the current model.
+ /// The to add.
+ public static void AddModelError(this ModelStateDictionary modelState, Expression> expression, Exception exception)
+ {
+ modelState.AddModelError(GetExpressionText(expression), exception);
+ }
+
+ ///
+ /// Removes the specified from the .
+ ///
+ /// The type of the model.
+ /// The instance this method extends.
+ /// An expression to be evaluated against an item in the current model.
+ ///
+ /// true if the element is successfully removed; otherwise, false.
+ /// This method also returns false if was not found in the model-state dictionary.
+ ///
+ public static bool Remove(this ModelStateDictionary modelState, Expression> expression)
+ {
+ return modelState.Remove(GetExpressionText(expression));
+ }
+
+ ///
+ /// Removes all the entries for the specified from the .
+ ///
+ /// The type of the model.
+ /// The instance this method extends.
+ /// An expression to be evaluated against an item in the current model.
+ public static void RemoveAll(this ModelStateDictionary modelState, Expression> expression)
+ {
+ string modelKey = GetExpressionText(expression);
+ if (string.IsNullOrEmpty(modelKey))
+ {
+ var modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(TModel));
+
+ foreach (var property in modelMetadata.Properties)
+ {
+ var childKey = property.BinderModelName ?? property.PropertyName;
+ var entries = modelState.FindKeysWithPrefix(childKey).ToArray();
+ foreach (var entry in entries)
+ {
+ modelState.Remove(entry.Key);
+ }
+ }
+ }
+ else
+ {
+ var entries = modelState.FindKeysWithPrefix(modelKey).ToArray();
+ foreach (var entry in entries)
+ {
+ modelState.Remove(entry.Key);
+ }
+ }
+ }
+
+ private static string GetExpressionText(LambdaExpression expression)
+ {
+ // We check if expression is wrapped with conversion to object expression
+ // and unwrap it if necessary, because Expression>
+ // automatically creates a convert to object expression for expresions
+ // returning value types
+ var unaryExpression = expression.Body as UnaryExpression;
+
+ if (IsConversionToObject(unaryExpression))
+ {
+ return ExpressionHelper.GetExpressionText(Expression.Lambda(unaryExpression.Operand, expression.Parameters[0]));
+ }
+
+ return ExpressionHelper.GetExpressionText(expression);
+ }
+
+ private static bool IsConversionToObject(UnaryExpression expression)
+ {
+ return expression?.NodeType == ExpressionType.Convert &&
+ expression.Operand?.NodeType == ExpressionType.MemberAccess &&
+ expression.Type == typeof(object);
+ }
+ }
+}
diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ModelStateDictionaryExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ModelStateDictionaryExtensionsTest.cs
new file mode 100644
index 0000000000..b1e49feeb0
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ModelStateDictionaryExtensionsTest.cs
@@ -0,0 +1,332 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.AspNet.Mvc.ModelBinding;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc
+{
+ public class ModelStateDictionaryExtensionsTest
+ {
+ [Fact]
+ public void AddModelError_ForSingleExpression_AddsExpectedMessage()
+ {
+ // Arrange
+ var dictionary = new ModelStateDictionary();
+
+ // Act
+ dictionary.AddModelError(model => model.Text, "Message");
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+ var modelError = Assert.Single(modelState.Value.Errors);
+
+ Assert.Equal("Text", modelState.Key);
+ Assert.Equal("Message", modelError.ErrorMessage);
+ }
+
+ [Fact]
+ public void AddModelError_ForRelationExpression_AddsExpectedMessage()
+ {
+ // Arrange
+ var dictionary = new ModelStateDictionary();
+
+ // Act
+ dictionary.AddModelError(model => model.Child.Text, "Message");
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+ var modelError = Assert.Single(modelState.Value.Errors);
+
+ Assert.Equal("Child.Text", modelState.Key);
+ Assert.Equal("Message", modelError.ErrorMessage);
+ }
+
+ [Fact]
+ public void AddModelError_ForImplicitlyCastedToObjectExpression_AddsExpectedMessage()
+ {
+ // Arrange
+ var dictionary = new ModelStateDictionary();
+
+ // Act
+ dictionary.AddModelError(model => model.Child.Value, "Message");
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+ var modelError = Assert.Single(modelState.Value.Errors);
+
+ Assert.Equal("Child.Value", modelState.Key);
+ Assert.Equal("Message", modelError.ErrorMessage);
+ }
+
+ [Fact]
+ public void AddModelError_ForNotModelsExpression_AddsExpectedMessage()
+ {
+ // Arrange
+ var variable = "Test";
+ var dictionary = new ModelStateDictionary();
+
+ // Act
+ dictionary.AddModelError(model => variable, "Message");
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+ var modelError = Assert.Single(modelState.Value.Errors);
+
+ Assert.Equal("variable", modelState.Key);
+ Assert.Equal("Message", modelError.ErrorMessage);
+ }
+
+ [Fact]
+ public void AddModelError_ForSingleExpression_AddsExpectedException()
+ {
+ // Arrange
+ var exception = new Exception();
+ var dictionary = new ModelStateDictionary();
+
+ // Act
+ dictionary.AddModelError(model => model.Text, exception);
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+ var modelError = Assert.Single(modelState.Value.Errors);
+
+ Assert.Equal("Text", modelState.Key);
+ Assert.Same(exception, modelError.Exception);
+ }
+
+ [Fact]
+ public void AddModelError_ForRelationExpression_AddsExpectedException()
+ {
+ // Arrange
+ var exception = new Exception();
+ var dictionary = new ModelStateDictionary();
+
+ // Act
+ dictionary.AddModelError(model => model.Child.Text, exception);
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+ var modelError = Assert.Single(modelState.Value.Errors);
+
+ Assert.Equal("Child.Text", modelState.Key);
+ Assert.Same(exception, modelError.Exception);
+ }
+
+ [Fact]
+ public void AddModelError_ForImplicitlyCastedToObjectExpression_AddsExpectedException()
+ {
+ // Arrange
+ var exception = new Exception();
+ var dictionary = new ModelStateDictionary();
+
+ // Act
+ dictionary.AddModelError(model => model.Child.Value, exception);
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+ var modelError = Assert.Single(modelState.Value.Errors);
+
+ Assert.Equal("Child.Value", modelState.Key);
+ Assert.Same(exception, modelError.Exception);
+ }
+
+ [Fact]
+ public void AddModelError_ForNotModelsExpression_AddsExpectedException()
+ {
+ // Arrange
+ var variable = "Test";
+ var exception = new Exception();
+ var dictionary = new ModelStateDictionary();
+
+ // Act
+ dictionary.AddModelError(model => variable, exception);
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+ var modelError = Assert.Single(modelState.Value.Errors);
+
+ Assert.Equal("variable", modelState.Key);
+ Assert.Same(exception, modelError.Exception);
+ }
+
+ [Fact]
+ public void Remove_ForSingleExpression_RemovesModelStateKey()
+ {
+ // Arrange
+ var dictionary = new ModelStateDictionary();
+ dictionary.Add("Text", new ModelState());
+
+ // Act
+ dictionary.Remove(model => model.Text);
+
+ // Assert
+ Assert.Empty(dictionary);
+ }
+
+ [Fact]
+ public void Remove_ForRelationExpression_RemovesModelStateKey()
+ {
+ // Arrange
+ var dictionary = new ModelStateDictionary();
+ dictionary.Add("Child.Text", new ModelState());
+
+ // Act
+ dictionary.Remove(model => model.Child.Text);
+
+ // Assert
+ Assert.Empty(dictionary);
+ }
+
+ [Fact]
+ public void Remove_ForImplicitlyCastedToObjectExpression_RemovesModelStateKey()
+ {
+ // Arrange
+ var dictionary = new ModelStateDictionary();
+ dictionary.Add("Child.Value", new ModelState());
+
+ // Act
+ dictionary.Remove(model => model.Child.Value);
+
+ // Assert
+ Assert.Empty(dictionary);
+ }
+
+ [Fact]
+ public void Remove_ForNotModelsExpression_RemovesModelStateKey()
+ {
+ // Arrange
+ var variable = "Test";
+ var dictionary = new ModelStateDictionary();
+ dictionary.Add("variable", new ModelState());
+
+ // Act
+ dictionary.Remove(model => variable);
+
+ // Assert
+ Assert.Empty(dictionary);
+ }
+
+ [Fact]
+ public void RemoveAll_ForSingleExpression_RemovesModelStateKeys()
+ {
+ // Arrange
+ var state = new ModelState();
+ var dictionary = new ModelStateDictionary();
+
+ dictionary.Add("Key", state);
+ dictionary.Add("Text", new ModelState());
+ dictionary.Add("Text.Length", new ModelState());
+
+ // Act
+ dictionary.RemoveAll(model => model.Text);
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+
+ Assert.Equal("Key", modelState.Key);
+ Assert.Same(state, modelState.Value);
+ }
+
+ [Fact]
+ public void RemoveAll_ForRelationExpression_RemovesModelStateKeys()
+ {
+ // Arrange
+ var state = new ModelState();
+ var dictionary = new ModelStateDictionary();
+
+ dictionary.Add("Key", state);
+ dictionary.Add("Child", new ModelState());
+ dictionary.Add("Child.Text", new ModelState());
+
+ // Act
+ dictionary.RemoveAll(model => model.Child);
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+
+ Assert.Equal("Key", modelState.Key);
+ Assert.Same(state, modelState.Value);
+ }
+
+ [Fact]
+ public void RemoveAll_ForImplicitlyCastedToObjectExpression_RemovesModelStateKeys()
+ {
+ // Arrange
+ var state = new ModelState();
+ var dictionary = new ModelStateDictionary();
+
+ dictionary.Add("Child", state);
+ dictionary.Add("Child.Value", new ModelState());
+
+ // Act
+ dictionary.RemoveAll(model => model.Child.Value);
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+
+ Assert.Equal("Child", modelState.Key);
+ Assert.Same(state, modelState.Value);
+ }
+
+ [Fact]
+ public void RemoveAll_ForNotModelsExpression_RemovesModelStateKeys()
+ {
+ // Arrange
+ var variable = "Test";
+ var state = new ModelState();
+ var dictionary = new ModelStateDictionary();
+
+ dictionary.Add("Key", state);
+ dictionary.Add("variable", new ModelState());
+ dictionary.Add("variable.Text", new ModelState());
+ dictionary.Add("variable.Value", new ModelState());
+
+ // Act
+ dictionary.RemoveAll(model => variable);
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+
+ Assert.Equal("Key", modelState.Key);
+ Assert.Same(state, modelState.Value);
+ }
+
+ [Fact]
+ public void RemoveAll_ForModelExpression_RemovesModelPropertyKeys()
+ {
+ // Arrange
+ var state = new ModelState();
+ var dictionary = new ModelStateDictionary();
+
+ dictionary.Add("Key", state);
+ dictionary.Add("Text", new ModelState());
+ dictionary.Add("Child", new ModelState());
+ dictionary.Add("Child.Text", new ModelState());
+ dictionary.Add("Child.NoValue", new ModelState());
+
+ // Act
+ dictionary.RemoveAll(model => model);
+
+ // Assert
+ var modelState = Assert.Single(dictionary);
+
+ Assert.Equal("Key", modelState.Key);
+ Assert.Same(state, modelState.Value);
+ }
+
+ private class TestModel
+ {
+ public string Text { get; set; }
+
+ public ChildModel Child { get; set; }
+ }
+
+ private class ChildModel
+ {
+ public int Value { get; set; }
+ public string Text { get; set; }
+ }
+ }
+}