diff --git a/src/EFCore/ModelBuilderExtensions.cs b/src/EFCore/ModelBuilderExtensions.cs
new file mode 100644
index 00000000000..1f41d884d7c
--- /dev/null
+++ b/src/EFCore/ModelBuilderExtensions.cs
@@ -0,0 +1,55 @@
+// 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.Reflection;
+
+namespace Microsoft.EntityFrameworkCore
+{
+ ///
+ /// Entity Framework related extension methods.
+ ///
+ public static class ModelBuilderExtensions
+ {
+ ///
+ /// Applies configuration from all instances that are defined in provided assembly.
+ ///
+ /// The instance of to modify
+ /// The assembly to scan
+ /// Optional predicate to filter types within the assembly
+ ///
+ /// The same instance so that additional configuration calls can be chained.
+ ///
+ public static ModelBuilder ApplyEntityTypeConfigurations(this ModelBuilder modelBuilder, Assembly assembly, Func predicate = null)
+ {
+ var method = typeof(ModelBuilder)
+ .GetMethods()
+ .Single(
+ e => e.Name == nameof(modelBuilder.ApplyConfiguration)
+ && e.ContainsGenericParameters
+ && e.GetParameters().SingleOrDefault()?.ParameterType?.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>));
+ foreach (var type in assembly.GetTypes())
+ {
+ // Only accept types that contain a parameterless constrictor, are not abstract and satisfy a predicate if it was used.
+ if (type.GetConstructor(Type.EmptyTypes) == null || type.IsAbstract || (!predicate?.Invoke(type) ?? false))
+ {
+ continue;
+ }
+ var @interface = type.GetInterfaces().FirstOrDefault(
+ i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>));
+ if (@interface == null)
+ {
+ continue;
+ }
+
+
+ var configuration = Activator.CreateInstance(type);
+ var target = method.MakeGenericMethod(@interface.GenericTypeArguments[0]);
+ target.Invoke(modelBuilder, new[] { configuration });
+ }
+
+ return modelBuilder;
+ }
+ }
+}
diff --git a/test/EFCore.Tests/ModelBuilding/IEntityTypeConfigurationAssemblyScanTest.cs b/test/EFCore.Tests/ModelBuilding/IEntityTypeConfigurationAssemblyScanTest.cs
new file mode 100644
index 00000000000..d1535e1abf2
--- /dev/null
+++ b/test/EFCore.Tests/ModelBuilding/IEntityTypeConfigurationAssemblyScanTest.cs
@@ -0,0 +1,108 @@
+// 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 Microsoft.EntityFrameworkCore.Metadata.Builders;
+using Microsoft.EntityFrameworkCore.TestUtilities;
+using Xunit;
+
+namespace Microsoft.EntityFrameworkCore.ModelBuilding
+{
+ public abstract partial class ModelBuilderTest
+ {
+ private static bool _customerConfigurationCalled;
+ private static bool _customerConfiguration2Called;
+ private static bool _abstractClassCalled;
+ private static bool _abstractClassImplCalled;
+
+ protected ModelBuilderTest()
+ {
+ _customerConfigurationCalled = false;
+ _customerConfiguration2Called = false;
+ _abstractClassCalled = false;
+ _abstractClassImplCalled = false;
+ }
+
+ public class ModelBuilderExtensionsTest : ModelBuilderTest
+ {
+ [Fact]
+ public void Should_scan_assemblies()
+ {
+ var builder = InMemoryTestHelpers.Instance.CreateConventionBuilder();
+ builder.ApplyEntityTypeConfigurations(typeof(IEntityTypeConfigurationTest).Assembly);
+
+ Assert.True(_customerConfigurationCalled);
+ Assert.True(_customerConfiguration2Called);
+ Assert.False(_abstractClassCalled);
+ Assert.True(_abstractClassImplCalled);
+ }
+
+ [Fact]
+ public void Should_support_filtering()
+ {
+ var builder = InMemoryTestHelpers.Instance.CreateConventionBuilder();
+ builder.ApplyEntityTypeConfigurations(typeof(ModelBuilderExtensionsTest).Assembly, type => type.Name == "CustomerConfiguration");
+
+ Assert.True(_customerConfigurationCalled);
+ Assert.False(_customerConfiguration2Called);
+ Assert.False(_abstractClassCalled);
+ Assert.False(_abstractClassImplCalled);
+
+ var entityType = builder.Model.FindEntityType(typeof(Customer));
+ Assert.Equal(nameof(Customer.AlternateKey), entityType.GetKeys().Single().Properties.Single().Name);
+ Assert.Equal(200, entityType.FindProperty(nameof(Customer.Name)).GetMaxLength());
+ }
+
+ [Fact]
+ public void Should_skip_abstract_classes()
+ {
+ var builder = InMemoryTestHelpers.Instance.CreateConventionBuilder();
+ builder.ApplyEntityTypeConfigurations(typeof(ModelBuilderExtensionsTest).Assembly, type => type.Name == "AbstractCustomerConfiguration");
+
+ Assert.False(_customerConfigurationCalled);
+ Assert.False(_customerConfiguration2Called);
+ Assert.False(_abstractClassCalled);
+ Assert.False(_abstractClassImplCalled);
+ }
+
+ private class CustomerConfiguration : IEntityTypeConfiguration
+ {
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasKey(c => c.AlternateKey);
+
+ builder.Property(c => c.Name).HasMaxLength(200);
+
+ _customerConfigurationCalled = true;
+ }
+ }
+
+ private class CustomerConfiguration2 : IEntityTypeConfiguration
+ {
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.Property(c => c.Name).HasMaxLength(1000);
+
+ _customerConfiguration2Called = true;
+ }
+ }
+
+ private abstract class AbstractCustomerConfiguration : IEntityTypeConfiguration
+ {
+ public virtual void Configure(EntityTypeBuilder builder)
+ {
+ _abstractClassCalled = true;
+ }
+ }
+
+ private class AbstractCustomerConfigurationImpl : AbstractCustomerConfiguration
+ {
+ public override void Configure(EntityTypeBuilder builder)
+ {
+ _abstractClassImplCalled = true;
+ }
+ }
+ }
+ }
+}