Vine aquí buscando las mismas respuestas. Resulta que el problema es que JPA no sabe que su objeto está sucio. Esto se resolvió implementando métodos equals()/hashcode() en estos objetos complejos. En su ejemplo, implemente equals y hashcode para ProjectProperty
Una vez hecho esto, JPA puede identificar a través de estos métodos que el objeto subyacente está sucio y se convierte y persiste.