I want to begin by mentioning that Godot 4.4 will have typed dictionaries. And I intend to use them to replace my solution once it is stable.
Suport for enum as key is not yet merged at time of writing (see #100512). Yet, I believe this feature would be just what you want.
You can iterate over the values of the enum (Since you have a named enum, you can access it as dictionary) and output the properties in _get_property_list, and handle them in _get and _set.
This is working code (tested in Godot 4.3):
@tool
extends Node
enum Payload {
IRON,
MERCURY,
SULPHUR,
}
@export_storage var textures:Array[Texture2D] = []
func _get_property_list() -> Array[Dictionary]:
var result:Array[Dictionary] = []
result.append(
{
name = "Tex",
type = TYPE_NIL,
hint_string = "tex_",
usage = PROPERTY_USAGE_GROUP
}
)
for key:String in Payload:
result.append(
{
name = "tex_" + key,
type = TYPE_OBJECT,
hint = PROPERTY_HINT_RESOURCE_TYPE,
hint_string = "Texture2D",
usage = PROPERTY_USAGE_EDITOR
}
)
return result
func _get(property:StringName) -> Variant:
if not property.begins_with("tex_"):
return null
property = property.trim_prefix("tex_")
if not Payload.has(property):
return null
if textures.size() != Payload.size():
textures.resize(Payload.size())
var enum_value:int = Payload[property]
return textures[enum_value]
func _set(property:StringName, value:Variant) -> bool:
if not property.begins_with("tex_"):
return false
property = property.trim_prefix("tex_")
if not Payload.has(property):
return false
if textures.size() != Payload.size():
textures.resize(Payload.size())
var enum_value:int = Payload[property]
textures[enum_value] = value
return true

Another option is to have for the inspector a propery which type is the enum, and a property which type is a texture, and then using getter and setter, we map to the actual values.
This is working code (tested in Godot 4.3):
@tool
extends Node
enum Payload {
IRON,
MERCURY,
SULPHUR,
}
@export_storage var textures:Array[Texture2D] = []
@export var current:Payload
@export var texture:Texture2D:
get:
if textures.size() != Payload.size():
textures.resize(Payload.size())
return textures[current]
set(mod_value):
if textures.size() != Payload.size():
textures.resize(Payload.size())
textures[current] = mod_value
func _validate_property(property: Dictionary) -> void:
match property.name:
"current", "texture":
property.usage = PROPERTY_USAGE_EDITOR

Notes
- With either of these code snippets adding new enum values does not imply extra effort, since this generates the properties based on the values of the enum.
- Both code snippets check the size of the array on every access, which is not much trouble, but an alternative is to set the size of the array in
_init.
- Both code snippets assume the enum has consecutive integer keys (which is the default). If it is not the case, you could move from an array to a dictionary to hold the textures.
- In both code snippets I'm using
@export_storage so Godot stores the underlying property. And PROPERTY_USAGE_EDITOR is used to tell Godot to show a property in the inspector but not store it.
And finally, I want to mention that yet another option is to implement a custom property inspector. However, I don't think it is worth the effort for this case.