When working with Entity Framework (EF), you may have noticed that it automatically pluralizes entity names when generating database table names — a Product entity maps to a Products table. This behavior is powered by pluralization services built into .NET. This article explores how pluralization works in .NET, how to customize it, and modern alternatives that offer broader language support and better handling of irregular words.
What is PluralizationService?
The PluralizationService class lives in the System.Data.Entity.Design.PluralizationServices namespace. It provides methods to convert English words between their singular and plural forms.
Basic Uso
using System.Data.Entity.Design.PluralizationServices;
using System.Globalization;
// Create a PluralizationService instance for English
PluralizationService pluralizer = PluralizationService.CreateService(
new CultureInfo("en-US")
);
// Pluralize words
Console.WriteLine(pluralizer.Pluralize("Category")); // "Categories"
Console.WriteLine(pluralizer.Pluralize("Person")); // "People"
Console.WriteLine(pluralizer.Pluralize("Mouse")); // "Mice"
Console.WriteLine(pluralizer.Pluralize("Child")); // "Children"
// Singularize words
Console.WriteLine(pluralizer.Singularize("Products")); // "Product"
Console.WriteLine(pluralizer.Singularize("Geese")); // "Goose"
Console.WriteLine(pluralizer.Singularize("Octopi")); // "Octopus"
Important Notes
PluralizationServiceis an abstract class. You must use theCreateServicestatic method to get an instance.- Only English (en-US) is supported. Passing any other culture will throw a
NotImplementedException. - The service handles many irregular words but is not perfect for all edge cases.
Checking if a Word is Already Plural or Singular
// Check if a word is already in its plural form
bool isPlural = pluralizer.IsPlural("Categories"); // true
bool isSingular = pluralizer.IsSingular("Category"); // true
// Use this to avoid double-pluralizing
string word = "People";
if (!pluralizer.IsPlural(word))
{
word = pluralizer.Pluralize(word);
}
Entity Framework Pluralization
How EF Uses Pluralization
Entity Framework uses pluralization in several places:
- Table name generation — A
Customerentity class maps to aCustomerstable - Navigation property naming — Collection navigation properties are pluralized
- Database-first model generation — Table names are singularized to create entity class names
EF6: PluralizingTableNameConvention
In Entity Framework 6, pluralization is controlled by the PluralizingTableNameConvention:
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
public class MyDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Disable automatic pluralization of table names
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
With the convention removed, the Product entity maps to a Product table instead of Products.
EF Core: No Automatic Pluralization by Default
In EF Core, table names default to the DbSet property name, not a pluralized version of the entity name:
public class MyDbContext : DbContext
{
// Table will be named "Products" (the property name, not pluralized from "Product")
public DbSet<Product> Products { get; set; }
}
If you want explicit control over table names:
// Using data annotations
[Table("tbl_Products")]
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
// Using Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().ToTable("tbl_Products");
}
Custom Pluralization Rules
Adding Custom Mappings in EF6
You can add custom word mappings to handle domain-specific terms or words the default service gets wrong:
using System.Data.Entity.Infrastructure.Pluralization;
public class CustomPluralizationService : IPluralizationService
{
private readonly IPluralizationService _defaultService;
private readonly Dictionary<string, string> _customPlurals;
private readonly Dictionary<string, string> _customSingulars;
public CustomPluralizationService()
{
_defaultService = new EnglishPluralizationService();
_customPlurals = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "Terminus", "Termini" },
{ "Campus", "Campuses" },
{ "Status", "Statuses" },
{ "Corpus", "Corpora" }
};
_customSingulars = _customPlurals.ToDictionary(x => x.Value, x => x.Key,
StringComparer.OrdinalIgnoreCase);
}
public string Pluralize(string word)
{
return _customPlurals.TryGetValue(word, out var plural)
? plural
: _defaultService.Pluralize(word);
}
public string Singularize(string word)
{
return _customSingulars.TryGetValue(word, out var singular)
? singular
: _defaultService.Singularize(word);
}
}
The IPluralizationService Interface
The IPluralizationService interface defines the contract for pluralization in Entity Framework:
namespace System.Data.Entity.Infrastructure.Pluralization
{
public interface IPluralizationService
{
string Pluralize(string word);
string Singularize(string word);
}
}
You can register a custom implementation with EF using a DbConfiguración class:
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetPluralizationService(new CustomPluralizationService());
}
}
EF Core Custom Pluralization
In EF Core, you can implement IPluralizer for design-time tools (like scaffolding):
using Microsoft.EntityFrameworkCore.Design;
public class CustomPluralizer : IPluralizer
{
public string Pluralize(string identifier)
{
// Your custom logic here
return identifier + "Set";
}
public string Singularize(string identifier)
{
if (identifier.EndsWith("Set"))
return identifier.Substring(0, identifier.Length - 3);
return identifier;
}
}
Register it in a design-time services class:
public class MyDesignTimeServices : IDesignTimeServices
{
public void ConfigureDesignTimeServices(IServiceCollection services)
{
services.AddSingleton<IPluralizer, CustomPluralizer>();
}
}
Humanizer: The Modern Alternative
The Humanizer library is a popular NuGet package that provides pluralization along with many other string manipulation features. It handles irregular words better than the built-in service and supports multiple languages.
Instalación
Install-Package Humanizer
Or with the .NET CLI:
dotnet add package Humanizer
Basic Pluralization with Humanizer
using Humanizer;
// Pluralize
"Person".Pluralize(); // "People"
"Man".Pluralize(); // "Men"
"Child".Pluralize(); // "Children"
"Octopus".Pluralize(); // "Octopi"
// Singularize
"People".Singularize(); // "Person"
"Mice".Singularize(); // "Mouse"
"Geese".Singularize(); // "Goose"
// Pluralize with count awareness
"person".ToQuantity(1); // "1 person"
"person".ToQuantity(5); // "5 people"
"person".ToQuantity(0); // "0 people"
Additional Humanizer Features
Humanizer offers much more than pluralization:
using Humanizer;
// Casing
"some_variable_name".Pascalize(); // "SomeVariableName"
"SomeVariableName".Underscore(); // "some_variable_name"
"some-css-class".Camelize(); // "someCssClass"
// Truncation
"Long string that needs truncating".Truncate(20); // "Long string that ..."
// Number to words
1.ToWords(); // "one"
42.ToOrdinalWords(); // "forty-second"
// TimeSpan humanization
TimeSpan.FromDays(3).Humanize(); // "3 days"
TimeSpan.FromMinutes(90).Humanize(2); // "1 hour, 30 minutes"
// DateTime humanization
DateTime.UtcNow.AddHours(-3).Humanize(); // "3 hours ago"
When to Use Which Approach
| Approach | Use Case |
|---|---|
| PluralizationService | Legacy EF6 projects that already depend on it |
| IPluralizationService | Customizing EF6 table name generation |
| IPluralizer (EF Core) | Customizing scaffolding in EF Core |
| Humanizer | General-purpose pluralization, UI display, string manipulation |
Common Pluralization Pitfalls
Be aware of words that trip up automated pluralization:
// Words that are the same in singular and plural
"sheep" -> "sheep" (not "sheeps")
"deer" -> "deer" (not "deers")
"fish" -> "fish" (not "fishs")
// Irregular plurals that may not be handled correctly
"matrix" -> "matrices"
"vertex" -> "vertices"
"index" -> "indices" (or "indexes" depending on context)
"appendix" -> "appendices"
// Words ending in -us
"cactus" -> "cacti"
"status" -> "statuses" (not "stati")
"virus" -> "viruses" (not "viri")
Always test pluralization with your domain-specific terms and add custom mappings for any words that are not handled correctly.
Resumen
Pluralization services in .NET provide automatic conversion between singular and plural word forms, which Entity Framework uses extensively for table naming and code generation. The built-in PluralizationService works for common English words, while the IPluralizationService interface allows you to inject custom rules. For modern .NET projects, the Humanizer library is the recommended approach — it provides better accuracy, multiple language support, and a rich set of additional string manipulation utilities.