Trims only maintain their user data if the JoinBreps operation returns a single Brep.
In general, It would be great if user data was maintained across operations like joins. User data would be far more useful if more operations respected it. It would be great if Rhino9 made a push to make user data more useful.
The difference is the disjoint-splitting step. When the join returns a single Brep, you get the joined result back as-is and the user data comes along. When it returns more than one, each piece gets rebuilt rather than copied, and user data doesn’t survive the rebuild.
I’ve logged a ticket to add a way of preserving it.
Two things to set expectations on. Trims are the easy case, since both faces keep their own trims through a join. Edges aren’t — joining two naked edges makes an edge that existed on neither input, so there’s nothing to inherit from.
The wider ask is a much bigger project. Boolean, Split, Trim and the rest build new Breps instead of copying existing ones, so there often isn’t an ancestor component to inherit from at all. That needs an answer per operation rather than a switch we can flip.