How to validate a unique field in Craft 3 element?
Here's my findings after some experimentation:


Elements and Records are two entirely separate entities. The Element is basically the core Craft database entry, while the Record is the additional database entry in a new table with your custom fields.
Validation should always be done on the element if you use the pattern used in the question, because saveElement() will call validate on the element itself, not the record. If you validate on the record and it fails ($record-&gt;save() returning false), the phantom element will still be created, but no record will refer to it. Yikes.
When validating on the element, some rules such as unique require access to the database, which is not bound to the element per se. In that case, you should map the targetClass parameter of the rule to the record class.
However that does mess up same-model detection with UniqueValidator: the validation will fail even if you're editing the current model, saying its unique field is already in use (by itself!).
Thankfully, you can use the filter parameter of the rule to manually ignore the current ID. However, you must make sure not to use that is the ID is null (i.e. when creating a new element), because != does not work with NULL values in SQL (you should be using IS NOT instead).


Summary: here's how to implement unique validation on the Element class:

    $rules[] = 
    [ 
        'myField', 
        'unique',
        'targetClass' =&gt; MyRecord::class,
        'filter' =&gt; function($query) {
            if ($this-&gt;id !== null) {
                $query-&gt;andWhere('`id` != :id', [ 'id' =&gt; $this-&gt;id ] );
            }
        }
    ];


That's it!