You can use an indexed access type combined with keyof to get what you want.
Code
type ValuesAsKeys<T extends Record<any, PropertyKey>, NewValue> = Record<T[keyof T], NewValue>
export const CODES = {
ALPHA: 'alpha',
OMEGA: 'omega',
} as const;
export type CODES_OBJECTS = ValuesAsKeys<typeof CODES, {}>
/* resolves to type CODES_OBJECTS = {
alpha: {};
omega: {};
} */
Playground Link
Explanation
The type ValuesAsKeys takes two generics -- T is the object whose values we want to use as keys (your CODES const) and NewValue is the value that we want to assign to those keys (here it's an empty object {} but you probably want something better).
In order to use the values of T as keys, we have to insist that the values of T are something that can be used as a key. We do that with T extends Record<any, PropertyKey> which uses the built-in type PropertyKey.
We can access the union of all values of T with T[keyof T] which is an indexed access type. We want to create a Record where those are the new keys. So we get Record<T[keyof T], NewValue>.
In order for typescript to see alpha and omega as their literal values and not just string, we use as const when creating CODES.
CODES is a value rather than a type, so we use typeof CODES as T.
Enum Version
The typescript is almost identical if using an enum. The only difference is that you don't need to add as const.
type ValuesAsKeys<T extends Record<any, PropertyKey>, NewValue> = Record<T[keyof T], NewValue>
enum CODES {
ALPHA = 'alpha',
OMEGA = 'omega',
}
export type CODES_OBJECTS = ValuesAsKeys<typeof CODES, {}>
Playground Link