C# example

How to convert a string to an enum in C#

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

Use Enum.TryParse: Enum.TryParse(text, ignoreCase: true, out Size size) returns true and sets size when text names a constant, and false otherwise. When a bad name is a bug rather than bad input, Enum.Parse<Size>("Medium") returns Size.Medium directly and throws ArgumentException on a miss. Both also accept numeric strings, so add Enum.IsDefined if only real constants are allowed.

C# enums are named integers, and the System.Enum class converts between the names and the values: Parse and TryParse go from a string to the enum, and ToString() goes back. They are a little more forgiving than people expect: they trim spaces, accept plain numbers and combine comma-separated names, which is useful for [Flags] enums and a surprise everywhere else. The examples below use one small Size enum throughout. To go from a number, see convert an int to an enum, and to list every constant, see loop through an enum. Each example runs on this page: hit Run, then edit the code and run it again.

1Enum.TryParse: ignore case, no exceptionsRecommended

Enum.TryParse returns a bool and hands the value back through an out parameter, so a bad string is an ordinary false, not an exception. Pass ignoreCase: true for anything a person typed. The one trap is the out value on failure: it is default(Size), which is whichever constant equals 0, so code that ignores the return value silently gets the first constant. Wrapping the call in a helper that returns Size? makes a miss impossible to confuse with a real value.

Program.cs

Output

Prints Parsed: Large, then False Small: the failed parse of "XL" still set bad, to Small. The helper reads "medium" and " Large " as Medium and Large (surrounding spaces are trimmed), and the code "XL", the empty string and null all print no match. A null input is safe: TryParse returns false rather than throwing. Then ?? Size.Medium picks a default and prints Medium. The generic ParseEnum<TEnum> works for any enum, here the built-in DayOfWeek: "friday" gives Friday, and the abbreviation "Fri" gives null, so the last line is True. The where TEnum : struct, Enum constraint needs C# 7.3 or later.

2Enum.Parse<T>: the value or an exception

Enum.Parse<Size>(text) returns the value directly and throws when text doesn't match. That is the right behaviour when the string comes from somewhere you control, such as a config key or a value your own code saved, because a miss means a bug you want to hear about. The generic overload arrived in .NET Core 2.0. Older code uses Enum.Parse(typeof(Size), text), which returns object and needs a cast; that form is still the one to use when the enum type is only known at runtime as a Type.

Program.cs

Output

The successful calls print Medium, True, Large, ExtraLarge (matched case-insensitively from "extralarge") and Small (from " Small ", spaces trimmed). The failures show the messages you will see in logs: Requested value 'medium' was not found. for the wrong case, the same for 'XL', and Must specify valid information for parsing in the string. (Parameter 'value') for an empty string. null throws ArgumentNullException: Value cannot be null. (Parameter 'value'), which the same catch (ArgumentException) handles because it is a subclass. The null! only silences the nullable warning for the demo.

3Numbers and comma lists parse too

Both Parse and TryParse accept the underlying number as text, and they accept a comma-separated list of names, which they combine with a bitwise OR. Neither checks that the result is a named constant, so "42" succeeds and produces a Size that matches nothing. Enum.IsDefined (generic since .NET 5) catches that case, but not a number or list that happens to land on a real constant. If only names are valid, check the text itself before parsing.

Program.cs

Output

The first four lines are the surprise: "2" parses as Large, "42" and "-1" parse to values with no name (they print as 42 and -1, defined: False), and "Medium, Large" parses as ExtraLarge, because Medium is 1, Large is 2 and 1 | 2 is 3. ParseDefined rejects "42" but still returns Large and ExtraLarge for the other two. ParseName rejects all three and accepts only "large". On a [Flags] enum the comma list is the point: "Read, Write" parses to Read, Write and HasFlag(Access.Write) is True. For flags, skip IsDefined: it returns false for any combination that isn't itself a declared constant.

4Map your own strings to enum values

Enum names have to be valid identifiers, so they can't hold "XL" next to ExtraLarge, spaces like "Extra large", or a database code. Unlike Java, a C# enum can't carry fields, so the usual way to associate strings with enum values is a static class: an extension method with a switch expression for enum to string, and a dictionary built from it for string to enum. Building the dictionary from the same method keeps the two directions in sync.

Program.cs

Output

Prints XL and Extra large, then ExtraLarge for the code "XL", Medium for " m " (trimmed and matched with StringComparer.OrdinalIgnoreCase) and unknown code for "XXL". The round trip prints True for all four constants, from Small S True to ExtraLarge XL True. The _ arm is there because any int can be cast to Size: ((Size)42).ToCode() throws ArgumentOutOfRangeException: Specified argument was out of the range of valid values. (Parameter 'size'). If you'd rather keep the strings next to the constants, put a [Description("Extra large")] attribute on each one and read it with reflection (see the FAQ). It is slower, but it lives in one place.

5Which conversion should you use?

MethodMatchesOn no matchBest for
Enum.TryParse(s, true, out Size v)Name in any case, or a numberReturns falseUser input, query strings, files
Enum.Parse<Size>(s)Exact name, or a numberThrows ArgumentExceptionNames you wrote yourself: config keys, saved values
(Size)Enum.Parse(typeof(Size), s)Exact name, or a numberThrows ArgumentExceptionOld .NET Framework code, or a Type known only at runtime
TryParse + Enum.IsDefinedName in any case, or a defined numberReturns falseRejecting values like "42" with no name
Dictionary<string, Size>Your own code or labelTryGetValue returns falseExternal values like "XL" or "Extra large"
(Size)int.Parse(s)A numberAny int becomes a Size, named or notRarely: numbers change when constants are reordered

6Enum to string: ToString(), nameof and format strings

Going the other way is simpler. ToString() and string interpolation give the constant's name, which is exactly what Enum.Parse reads back. nameof(Size.Large) produces the same text at compile time, so it costs nothing at runtime and survives a rename. Format strings choose between the name (G), the number (D) and hex (X), and Enum.GetName returns null instead of a number when the value has no name.

Program.cs

Output

Prints ExtraLarge, Size: ExtraLarge and Large. The format strings give ExtraLarge 3 00000003, and ToString("D") gives 3. For (Size)42, Enum.GetName returns null while ToString() prints 42, so check for a number if you show enum names to users. Enum.GetNames<Size>() (.NET 5+; use Enum.GetNames(typeof(Size)) before that) lists Small, Medium, Large, ExtraLarge. A [Flags] value prints as Read, Delete, and parsing that text gives back the same value (True), so names round-trip cleanly through files and databases.

Frequently asked questions

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

For input you don't control, use Enum.TryParse(text, ignoreCase: true, out Size size): it returns false instead of throwing, and size is only meaningful when it returns true. For names you trust, Enum.Parse<Size>("Medium") returns Size.Medium and throws ArgumentException: Requested value 'medium' was not found. on a miss. On .NET Framework, use (Size)Enum.Parse(typeof(Size), text) or the generic Enum.TryParse<Size>, which has existed since .NET Framework 4.0.

Is Enum.Parse case-sensitive?

Yes, by default. Enum.Parse<Size>("medium") throws Requested value 'medium' was not found., while Enum.Parse<Size>("extralarge", ignoreCase: true) returns ExtraLarge. TryParse has the same ignoreCase parameter. Surrounding spaces are trimmed either way, so " Small " parses as Small.

Why does Enum.TryParse return true for a number like "42"?

Parse and TryParse accept the underlying number as text and never check that it names a constant, so "42" gives a Size that prints as 42. They also OR together comma-separated names: "Medium, Large" parses as ExtraLarge. Add Enum.IsDefined(size) to reject undefined numbers, and check that the text starts with a letter and has no comma if only names are allowed.

What does Enum.TryParse set the out value to when it fails?

default(TEnum), the value 0, which is usually the first constant. Enum.TryParse("XL", out Size bad) returns False and leaves bad as Small. Always check the return value, or wrap the call in a helper that returns Size? so a miss is null.

How do I get the string name of an enum value?

Call ToString() or put it in an interpolated string: Size.ExtraLarge.ToString() and $"{size}" both give ExtraLarge. nameof(Size.Large) gives Large at compile time. For a value that may not be defined, Enum.GetName(value) returns null, while ToString() returns the number, so (Size)42 prints as 42. ToString("D") gives the number of any value.

How do I associate a string with an enum value, or use spaces in the name?

Enum names can't contain spaces, so Enum.TryParse("Extra large", ignoreCase: true, out Size s) returns False. Keep the strings outside the enum: an extension method with a switch expression for enum to string and a Dictionary<string, Size> built from it for the reverse lookup. Or put [Description("Extra large")] on the constant and read it with typeof(Size).GetField(size.ToString())?.GetCustomAttribute<DescriptionAttribute>()?.Description, which returns Extra large (add using System.ComponentModel; and using System.Reflection;).

How do I serialize an enum as a string in JSON?

System.Text.Json writes enums as numbers by default, so a record holding Size.Large serializes as {"Size":2}. Add new JsonStringEnumConverter() to JsonSerializerOptions.Converters to get {"Size":"Large"}. With the converter, deserializing {"Size":"medium"} also works and gives Medium, because it matches names case-insensitively.

Run it yourself

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

C# playground