hover is not an event you can use with on. It is only a shorthand for the events mouseenter and mouseleave. So you have to use them with the correct names for your delegation.
As from the documentation:
The .hover() method binds handlers for both mouseenter and mouseleave
events. You can use it to simply apply behavior to an element during
the time the mouse is within the element.
So rewrite your listener like this:
$(document).on('mouseenter', '.portrait-image', function() {
console.log('hi');
});
$(document).on('mouseleave', '.portrait-image', function() {
console.log('bye');
});
Or like this:
$(document).on({
'mouseenter': function() {
console.log('hi');
},
'mouseleave' function() {
console.log('bye');
}
}, '.portrait-image');
To explain why only bye is shown:
Like seen in the documentation, on has up to four parameters. The last two are data and handler. Your hi callback is interpreted as data and will be ignored. The handler is the actual bye callback for the handler.
hover is a pseudo name in jQuery. It will do something like this:
$(document).on('mouseenter mouseleave', '.portrait-image', function() {
console.log('hi');
});
This means every time you enter OR leave, it will print bye.