Codec Provider for polymorphic object implementing a common Trait

What is the recommended way to implement a Codec Provider for a Trait which will choose the case class based on an attribute of the Trait?

Here is a short example:

I have the following Account Trait:

object AccountType extends Enumeration {

  type AccountType = Value

  val Administrator: Value = Value("administrator")
  val User: Value = Value("user")

trait Account {

  val id: ObjectId
  val `type`: AccountType
  val login: String
  val groups: Option[Seq[Group]]
  val certificate: Option[CFCertificate]
  val creationDate: Instant


And I have two case classes extending the Account Trait:

case class UserAccount(
  @BsonProperty("_id") id: ObjectId = new ObjectId(),
  `type`: AccountType = AccountType.User,
  login: String,
  groups: Option[Seq[Group]] = None,
  certificate: Option[CFCertificate],
  creationDate: Instant =
) extends Account

object UserAccount {
  implicit val userAccountCodecProvider: CodecProvider = Macros.createCodecProviderIgnoreNone[UserAccount]()

case class AdministratorAccount(
  @BsonProperty("_id") id: ObjectId = new ObjectId(),
  `type`: AccountType = AccountType.Administrator,
   login: String,
   groups: Option[Seq[Group]] = None,
   certificate: Option[CFCertificate],
   creationDate: Instant =
) extends Account

object AdministratorAccount {
  implicit val administratorAccountCodecProvider: CodecProvider = Macros.createCodecProviderIgnoreNone[AdministratorAccount]()

In the companion object of the Account Trait, I created the following implicit Codec Provider:

object Account {

  implicit val accountCodecProvider: CodecProvider = new CodecProvider {
    override def get[T](clazz: Class[T], registry: CodecRegistry): Codec[T] = {
      if (classOf[Account].isAssignableFrom(clazz)) {
        new Codec[Account] {
          override def encode(writer: BsonWriter, value: Account, encoderContext: EncoderContext): Unit = value match {
            case administratorAccount: AdministratorAccount => registry.get[AdministratorAccount](classOf[AdministratorAccount]).encode(writer, administratorAccount, encoderContext)
            case userAccount: UserAccount => registry.get[UserAccount](classOf[UserAccount]).encode(writer, userAccount, encoderContext)
            case other => throw new CodecConfigurationException(s"Unsupported Account type ${other.`type`}")

          override def getEncoderClass: Class[Account] = classOf[Account]

          override def decode(reader: BsonReader, decoderContext: DecoderContext): Account = {
            val document = decoderContext.decodeWithChildContext(new BsonDocumentCodec(), reader)
            val accountType = document.getString("type").getValue
            AccountType.withName(accountType) match {
              case AccountType.Administrator => registry.get[AdministratorAccount](classOf[AdministratorAccount]).decode(new BsonDocumentReader(document), decoderContext)
              case AccountType.User => registry.get[UserAccount](classOf[UserAccount]).decode(new BsonDocumentReader(document), decoderContext)
              case other => throw new CodecConfigurationException(s"Unsupported Account type $other")
      } else


Is this the recommended / idiomatic way to do so?

Furthermore, and as requested in the ticket Need architecture guidance with Codecs and Codec Providers, is there a way to avoid declaring all the codecs in a local registry in my Service class which manage Accounts (CRUD) but load them implicitly when required:

class AccountService @Inject() (implicit ec: ExecutionContext, mongoDbApi: MongoDbApi){

  private val codecRegistry: CodecRegistry = fromRegistries(