The *is-a* relationship (I think) can be expressed by either a class or an interface/trait, since both kinds of entities introduce a new type which can be subtyped. e.g. a String *is-a* Comparable, because it is a subtype of Comparable.

What I'm trying to do here is just introduce some very simple named types, with a single implementation for each type. I don't really think it merits an abstract class and subclass for each, although I don't think doing so would be bad *per se*. It would just feel "heavier" than it needs to be. Maybe it's personal preference.

Re: sealed traits, this means the Scala compiler guards against extending the trait elsewhere and also is able to provide exhaustiveness checking when pattern matching. Since we don't care about either case I don't think it is worth adding the extra keyword. In fact, the presence of the sealed keyword might imply that pattern matching is typical usage for these types, which would be confusing.