C# example

How to loop through an enum in C#

8 min read Updated Oct 2026 Runs in an isolated runtime
Quick answer

Loop over Enum.GetValues<T>(): foreach (Suit suit in Enum.GetValues<Suit>()). It returns a typed Suit[] (.NET 5+), so Enum.GetValues<Suit>().ToList() gives you a list and Enum.GetNames<Suit>() gives the names. On .NET Framework, use Enum.GetValues(typeof(Suit)) and let foreach cast each item.

An enum isn't a collection, so you can't foreach over the type itself. The System.Enum class reads its members for you instead: GetValues returns the values, GetNames the names. Since .NET 5 both have generic forms that return typed arrays, which is what the examples below use. They also show the older typeof form you will meet in existing code, how to get a List, and the cases where the values come back in an order, or a number, you might not expect. To convert between enums and numbers or strings, see convert an int to an enum and convert a string to an enum. Each example runs on this page: hit Run, then edit the code and run it again.

1Enum.GetValues<T>(): loop over every memberRecommended

Enum.GetValues<Suit>() returns a new Suit[] holding every member, so a plain foreach visits each one, already typed. Cast a member to int to see its number. Because the result is an ordinary array, indexing, Length and LINQ all work on it, and you can nest two loops to combine two enums.

Program.cs

Output

The loop prints Clubs = 0 through Spades = 3: members without an explicit value are numbered from 0. Then 4 suits: Clubs, Diamonds, Hearts, Spades. suits[^1] and suits.Max() both print Spades, and the Where filter prints Diamonds Hearts. The nested loops build 52 cards, first Two of Clubs, last Ace of Spades. The last line prints False: every call allocates a fresh array, so read it once into a variable (or a static readonly field) rather than calling it on every pass of a hot loop. The generic overload needs .NET 5 or later; the next section covers older frameworks.

2GetNames, and the older typeof(...) form

Enum.GetNames<Suit>() returns the member names as a string[]. Before .NET 5 neither method was generic: you passed typeof(Suit) and got back a plain Array from GetValues. That still works on every .NET version, and it is the form in most older answers and codebases. Name the type in the foreach and the loop casts each element for you; for LINQ, add Cast<Suit>() first.

Program.cs

Output

GetNames prints Clubs, Diamonds, Hearts, Spades. The non-generic GetValues really returns a Suit[] (that is what GetType() prints), but its static type is Array, so the compiler can't check what you do with the elements. The two loops print Clubs Diamonds Hearts Spades and CLUBS DIAMONDS HEARTS SPADES, and the LINQ query prints Diamonds, Hearts. The last loop shows the cost of that missing check: it reads DayOfWeek values into a Suit variable and prints Clubs Diamonds Hearts Spades 4 5 6 without any exception. The runtime converts between enums that share an underlying type, and 4 to 6 have no Suit name, so they print as numbers. With the generic overload you can write foreach (var suit in ...) and the loop variable takes the array's element type, so there is no cast to get wrong.

3Turn an enum into a List

The arrays from GetValues and GetNames convert like any other sequence: ToList(), or a collection expression with a spread (C# 12) that can target a List, an array or a HashSet. Project the members with Select when you need value and name pairs, for example to fill a dropdown or describe the enum in an API response.

Program.cs

Output

The first line prints Diamonds, Hearts, Spades | 4: removing Clubs from one list leaves the other untouched, because each is a separate copy. The names list prints Clubs, Diamonds, Hearts, Spades, and the records print as Option { Value = 0, Name = Clubs } through Option { Value = 3, Name = Spades }. The dictionary lookup prints 2, Except leaves Diamonds, Hearts, and the HashSet check prints True. On a version before C# 12, use ToList(), ToArray() or new HashSet<Suit>(...) in place of the [..] spreads.

4Which should you use?

MethodReturnsAvailable inBest for
Enum.GetValues<T>()T[].NET 5+Looping over the members in current .NET
Enum.GetNames<T>()string[].NET 5+Names only: labels, lists of accepted values
Enum.GetValues(typeof(T))Array (cast each item)Every version.NET Framework, or a Type known only at run time
Enum.GetNames(typeof(T))string[]Every versionNames on .NET Framework
[.. Enum.GetValues<T>()] or .ToList()List<T>C# 12 / .NET 5+A list you can add to or remove from
Enum.GetValuesAsUnderlyingType<T>()Array of int, byte, ….NET 7+The raw numbers, without casting each member

5Order, duplicate values and [Flags] enums

GetValues doesn't return members in the order you declared them. It sorts them by their numeric value, treated as unsigned, so negative values come last. Two names that share a value are two entries in GetNames but the same value twice in GetValues. And a [Flags] enum hands back every named member, including None and combinations such as ReadWrite, which is rarely what a loop over "the flags" wants.

Program.cs

Output

Status was declared as Active, Archived, Draft, Deleted, but the loop prints 0 Draft, 1 Active, 3 Archived and -1 Deleted last, since -1 is the largest number as an unsigned value. For Level, GetNames prints Low, Medium, Normal, High while GetValues prints Low, Medium, Medium, High: the value 2 appears twice and prints as Medium both times (which name ToString picks for a shared value isn't documented, so don't rely on it). Distinct() gives Low, Medium, High, hence 4 names, 3 distinct values. The flags enum returns None, Read, Write, ReadWrite, Delete; keeping the powers of two leaves Read, Write, Delete, and testing each against a value prints Read, Delete. Filtering out None matters: HasFlag(Access.None) is true for every value, so the unfiltered loop would report None, Read, Delete.

6A generic helper, and enums known only at run time

To write one method that loops over any enum, constrain its type parameter with where T : struct, Enum (the Enum constraint arrived in C# 7.3). That is exactly the constraint GetValues<T>() declares, so the helper can call it. When all you have is a Type object, from reflection or a plugin, fall back to the non-generic overloads and treat each item as object.

Program.cs

Output

The helper prints Suit (4): Clubs, Diamonds, Hearts, Spades and DayOfWeek (7): Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, so built-in enums work the same as your own. For the Type object, IsEnum prints True and the loop prints Read=1 Write=2 ReadWrite=3; Convert.ToInt32 reads the number out of the boxed value. GetValuesAsUnderlyingType returns the numbers in the enum's own underlying type: System.Byte[]: 10, 20, 30 for an enum declared : byte, which GetUnderlyingType confirms as System.Byte. The Next helper prints Spades Clubs Sunday, wrapping from the last member back to the first.

7Loop with display text: [Description] or a switch

Member names like Pending rarely make good labels. One common pattern stores the text on each member with [Description] from System.ComponentModel and reads it back through reflection while you loop. If you control the enum and only need one set of labels, a switch expression does the same job with no reflection at all.

Program.cs

Output

The loop prints Pending Waiting for payment, Shipped Shipped, on its way and Delivered Delivered to the customer, and Cancelled Cancelled for the member without an attribute, where the helper falls back to the name. The tuple list prints its second item as (1, Shipped, on its way), and the switch version prints Waiting / On its way / Done / Cancelled. Reflection is slow compared with a switch, so if you read descriptions on a hot path, build a dictionary of them once and look them up there. Code that uses [Display(Name = ...)] from System.ComponentModel.DataAnnotations reads it the same way, with GetCustomAttribute<DisplayAttribute>()?.Name.

Frequently asked questions

How do I loop through all values of an enum in C#?

Use foreach (Suit suit in Enum.GetValues<Suit>()) on .NET 5 or later. On .NET Framework or .NET Core 3.1, use foreach (Suit suit in Enum.GetValues(typeof(Suit))); naming the type in the loop casts each item. Both visit every member, sorted by numeric value rather than declaration order.

How do I convert an enum to a List in C#?

Call Enum.GetValues<Suit>().ToList(), or write List<Suit> suits = [.. Enum.GetValues<Suit>()]; with a C# 12 collection expression. For the names, use Enum.GetNames<Suit>().ToList(). With the older API, add a cast first: Enum.GetValues(typeof(Suit)).Cast<Suit>().ToList().

Why is my loop variable an object when I use var with Enum.GetValues?

The non-generic Enum.GetValues(typeof(Suit)) returns Array, whose elements are typed object, so foreach (var v in ...) makes v an object, and v == Suit.Hearts fails with error CS0019: Operator '==' cannot be applied to operands of type 'object' and 'Suit'. Name the type instead (foreach (Suit v in ...)), or use Enum.GetValues<Suit>(), where var is inferred as Suit.

Does Enum.GetValues return values in declaration order?

No. It sorts by the numeric value, compared as unsigned, so an enum declared as Active = 1, Archived = 3, Draft = 0, Deleted = -1 loops as Draft, Active, Archived, Deleted. For the common case where members are numbered 0, 1, 2 in order, the two orders match. If the order matters, sort the array yourself.

How do I count the number of items in an enum?

Use Enum.GetNames<Suit>().Length, which is 4 for a four-member enum (Enum.GetValues<Suit>().Length gives the same). If two names share a value, both still count: for Low = 1, Medium = 2, High = 3, Normal = 2 both lengths are 4, and Enum.GetValues<Level>().Distinct().Count() gives 3 distinct values.

How do I loop over only the flags that are set in a [Flags] enum?

Loop over the single-bit members and test each with HasFlag: Enum.GetValues<Access>().Where(f => int.IsPow2((int)f) && granted.HasFlag(f)). Skip None and combined members such as ReadWrite, since HasFlag(Access.None) is always true. To just display them, granted.ToString() already prints Read, Delete for a [Flags] enum.

Is Enum.GetValues slow? Should I cache it?

Each call allocates a new array (ReferenceEquals(Enum.GetValues<Suit>(), Enum.GetValues<Suit>()) is False), so calling it once per loop is fine, but inside a hot loop read it once. A static readonly Suit[] AllSuits = Enum.GetValues<Suit>(); field caches it for the life of the program.

Run it yourself

Open any of these in the full C# editor to tweak, run and share.

C# playground