We created a home-grown tool that runs queries specified in one or more files during the build and generates enumerated type classes, one for each reference data table. At a minimum the tool only requires reference data tables to have two columns: a primary key (with unique constraints) and a string. Each enum instance has a name generated from the string (after getting munged through an algorithm to convert the name into upper case, replace whitespace and other invalid characters to underscores, etc.).
The tool is flexible enough to allow for additional properties on each value; e.g., a "display name", a "description", maybe associated numeric values, and other simple types. We also generate static methods on the enum class to get various subsets of values; there's always at least one that returns all values, but we can have additional ones generated based on SQL queries. For a color enum, we might have a "primaryColors()" static method, for example. Additional static methods are generated to look up a value based on its key; e.g.,
public static Color valueOf(int key);
The enums make it easy and more readable to use well-known reference values in code; e.g.,
if (selectedColor == Colors.RED) {
.
.
.
}
This does have a disadvantage of requiring an additional build step, but in our case that's far outweighed by the advantages: cleaner code, assurance that the UI, business logic, and database valid values are in sync, etc.
We've frequently talked about having a hybrid of a static mechanism as described above plus adding more dynamic behavior, but we've never actually felt it compelling enough to add to the complexity.