When a code contains the Java instanceof operator, many people will raise their eyebrows and say it is a no-no.  For example, in this other SO Q&A, the answer said:
Note that if you have to use that operator very often it is generally a hint that your design has some flaws. So in a well designed application you should have to use that operator as little as possible (of course there are exceptions to that general rule).
However, it does not further elaborate when the use of instanceof is okay, and when it is not.
I put some thinking on this, and articlate the following guideline. I thought this may have been discussed somewhere on the Internet, but I could not find it. Hence this question and asking for your comment:
Using
instanceofon an interface is okay; usinginstanceofon an implementation is not okay
Here is an example on the "okay" case.
Example: A catalog of animals, some (but not all) of them can fly
Animal.java
public interface Animal {
    String getName();
    String makeNoise();
}
CanFly.java
public interface CanFly {
    float getMaxInAirDistanceKm();
}
Cat.java
public class Cat implements Animal {
    @Override
    public String getName() {
        return "Cat";
    }
    @Override
    public String makeNoise() {
        return "meow";
    }
}
BaldEgale.java
public class BaldEagle implements Animal, CanFly {
    @Override
    public String getName() {
        return "BaldEagle";
    }
    @Override
    public String makeNoise() {
        return "whistle";
    }
    @Override
    public float getMaxInAirDistanceKm() {
        return 50;
    }
}
Catalog.java
import java.util.ArrayList;
import java.util.List;
public class Catalog {
    private List<Animal> animals = new ArrayList<>();
    public void putAnimal(Animal animal) {
        animals.add(animal);
    }
    public void showList() {
        animals.forEach(animal -> {
            StringBuilder sb = new StringBuilder();
            sb.append(animal.getName() + ": ");
            sb.append(animal.makeNoise() + " ");
            // this block exemplifies some processing that is 
            //   specific to CanFly animals
            if (animal instanceof CanFly) {
                sb.append(String.format(" (can stay in air for %s km)",
                        ((CanFly) animal).getMaxInAirDistanceKm()));
            }
            System.out.println(sb.toString());
        });
    }
    public static void main(String[] args){
        Catalog catalog = new Catalog();
        Cat cat = new Cat();
        BaldEagle baldEagle = new BaldEagle();
        catalog.putAnimal(cat);
        catalog.putAnimal(baldEagle);
        catalog.showList();
    }
}
Test Output
Cat: meow 
BaldEagle: whistle  (can stay in air for 50.0 km)
Updated 2019-10-09 Adding example for the "not-okay" case:
We could have dropped the CanFly interface, and in the showList() method, we apply the instanceof on the concrete implementation BaldEagle -- like this:
    public void showList() {
        animals.forEach(animal -> {
            StringBuilder sb = new StringBuilder();
            sb.append(animal.getName() + ": ");
            sb.append(animal.makeNoise() + " ");
            if (animal instanceof BaldEagle) {
                sb.append(String.format(" (can stay in air for %s km)",
                        ((BaldEagle) animal).getMaxInAirDistanceKm()));
            }
            System.out.println(sb.toString());
        });
    }
This approach is not okay because the code is now dependent on implementation, not interface.  It prevents, for example, swapping out another implementation representing Bald Eagle (e.g. BaldEagleImpl)
 
     
     
    