I'm a very big fan of the "object algebras" approach [0], which is essentially tagless final minus the automatic instance resolution you get with typeclasses. It works great even in fairly restrictive type systems like Java's.
[0]: https://www.cs.utexas.edu/~wcook/Drafts/2012/ecoop2012.pdf
Some common approaches:
- Tagless final style: https://okmij.org/ftp/tagless-final/
- Datatype-generic programming: https://markkarpov.com/tutorial/generics.html
- Polymorphic records and variants: https://www.cl.cam.ac.uk/teaching/1415/L28/rows.pdf