Another one: they conflate Type and (Locator) Instance in a unique way that just about nothing else in TS does. Those are two very different things with the same name with Typescript's (antiquated) enums.
There are too many ways to accidentally import/redeclare/rescope the Type of an enum so that TS "knows" the Type, but because that type (generally) has the same "name" as the most likely (Locator) Instance it assumes the same access applies leaving runtime errors behind when that Instance isn't actually imported/available. Typescript has no easy way to tell the difference between access to the Type isn't access to the (Locator) Instance (nor vice versa). Reasoning about those runtime errors or preventing them is additionally tough for people too because of the same "name" problem for two different things.
This is something that's painfully hard to avoid in cases where you are trying to encapsulate an API's Types separate from its imports/exports because they might be introduced or manipulated at runtime (plugins, sandboxes, proxies, etc). Unfortunately, this is also too easy to accidentally do even when you aren't intentionally doing something complicated like that (trying to generate automated .d.ts files in a bundling toolchain, for example, when APIs are in the boundary space between unintentional public API and internal tree-shaking or optimized symbol renaming).
I just finished removing them from a major project. Here’s a few of my personal notes:
1. They don’t play well with duck typing. (Eg. show me a subset of an enum)
2. They require an import every time you want to utilize them.
3. They are pretty wordy compared to union strings.
4. Their string value version encourages misuse as a key-value pair.
5. Unless you use the string value version, they suck to debug because logs just show 0,1,2,3.